Do faktycznego użycia należy użyć odpowiedzi, która została najwyżej oceniona .
Chciałbym jednak omówić różne zepsute i na wpół wykonalne podejścia ps
oraz wiele ostrzeżeń, jakie mają, ponieważ wciąż widzę, jak ludzie z nich korzystają.
Ta odpowiedź to tak naprawdę odpowiedź na pytanie „Dlaczego nie użyć ps
i grep
poradzić sobie z blokowaniem w powłoce?”
Zepsute podejście # 1
Po pierwsze, podejście podane w innej odpowiedzi, które ma kilka pozytywnych opinii, mimo że nie działa (i nigdy nie mogło) działać i najwyraźniej nigdy nie zostało przetestowane:
running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do
echo Already locked
exit 6
fi
Naprawmy błędy składniowe i zepsute ps
argumenty i uzyskajmy:
running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
echo Already locked
exit 6
fi
Ten skrypt zawsze kończy działanie 6, za każdym razem, bez względu na to, jak go uruchomisz.
Jeśli uruchomisz go ./myscript
, ps
wynik będzie po prostu taki 12345 -bash
, który nie będzie pasował do wymaganego ciągu 12345 bash ./myscript
, więc to się nie powiedzie.
Jeśli go uruchomisz bash myscript
, wszystko stanie się bardziej interesujące. Proces bash widły do uruchomienia rurociągu, a dziecko powłoka uruchamia ps
i grep
. Zarówno powłoka oryginalna, jak i podrzędna zostaną wyświetlone w danych ps
wyjściowych, mniej więcej tak:
25793 bash myscript
25795 bash myscript
Nie jest to oczekiwany wynik $$ bash $0
, więc skrypt zostanie zamknięty.
Zepsute podejście # 2
Teraz, uczciwie wobec użytkownika, który napisał złamane podejście nr 1, zrobiłem coś podobnego, kiedy po raz pierwszy spróbowałem tego:
if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
echo >&2 "There are other copies of the script running; exiting."
ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
exit 1
fi
To prawie działa. Ale fakt rozwidlenia się, aby poprowadzić rurę, odrzuca to. Więc ten również zawsze wyjdzie.
Nierzetelne podejście # 3
pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
echo >&2 "There are other copies of this script running; exiting."
ps -fq "${not_this_process//$'\n'/ }"
exit 1
fi
Ta wersja pozwala uniknąć problemu rozwidlenia potoku w podejściu nr 2, najpierw pobierając wszystkie PID, które mają bieżący skrypt w argumentach wiersza poleceń, a następnie osobno filtrując tę listę pid, aby pominąć PID bieżącego skryptu.
Może to działać ... pod warunkiem, że żaden inny proces nie ma wiersza polecenia pasującego do $0
, a jeśli skrypt jest zawsze wywoływany w ten sam sposób (np. Jeśli jest wywoływany ze ścieżką względną, a następnie ścieżką bezwzględną, druga instancja nie zauważy pierwszej ).
Nierzetelne podejście # 4
A co jeśli pominiemy sprawdzanie pełnego wiersza poleceń, ponieważ może to nie oznaczać, że skrypt faktycznie działa, i lsof
zamiast tego sprawdzimy, aby znaleźć wszystkie procesy, które mają ten skrypt otwarty?
Cóż, tak, to podejście nie jest wcale takie złe:
if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running. Exiting to avoid conflicts."
ps >&2 -fq "${otherpids//$'\n'/ }"
exit 1
fi
Oczywiście, jeśli kopia skryptu jest uruchomiona, nowa instancja uruchomi się dobrze i będziesz mieć uruchomione dwie kopie .
Lub jeśli uruchomiony skrypt zostanie zmodyfikowany (np. Za pomocą Vima lub a git checkout
), wówczas „nowa” wersja skryptu uruchomi się bez problemu, ponieważ zarówno Vim, jak i git checkout
nowy plik (nowy i-węzeł) zamiast stary.
Jednakże, jeśli skrypt nie jest modyfikowana i nigdy kopiowane, to ta wersja jest bardzo dobra. Nie ma warunków wyścigu, ponieważ plik skryptu musi już być otwarty, aby można było sprawdzić czek.
Nadal mogą występować fałszywe alarmy, jeśli inny proces ma otwarty plik skryptu, ale pamiętaj, że nawet jeśli jest on otwarty do edycji w Vimie, vim tak naprawdę nie utrzymuje otwartego pliku skryptu, więc nie spowoduje to fałszywych alarmów.
Ale pamiętaj, nie używaj tego podejścia, jeśli skrypt może być edytowany lub kopiowany, ponieważ otrzymasz fałszywe negatywy, tj. Wiele instancji działających jednocześnie - więc fakt, że edycja za pomocą Vima nie daje fałszywych wyników pozytywnych, nie powinien mieć znaczenia do Ciebie. Wspominam go jednak, ponieważ podejście nr 3 nie daje wyników fałszywie dodatnich (tj odmawia start) jeśli masz skrypt otwarty z Vima.
Co więc zrobić?
Najwyższej głosowało odpowiedź na to pytanie daje solidne podejście.
Być może możesz napisać lepszy ... ale jeśli nie rozumiesz wszystkich problemów i zastrzeżeń we wszystkich powyższych podejściach, prawdopodobnie nie napiszesz metody blokowania, która omija je wszystkie.
kill
edycji; i wydaje się, że dobrą praktyką jest przechowywanie własnego pid w pliku blokującym, niż tylko dotykanie go.