Per un utilizzo effettivo, è necessario utilizzare la risposta più votata .
Tuttavia, voglio discutere alcuni diversi approcci rotti e semi-lavorabili usando ps
e le molte avvertenze che hanno, dal momento che continuo a vedere le persone li usano.
Questa risposta è davvero la risposta a "Perché non usare ps
e grep
gestire il blocco nella shell?"
Approccio rotto n. 1
In primo luogo, un approccio fornito in un'altra risposta che ha alcuni voti nonostante il fatto che non funzioni (e non potrebbe mai) funzionare e chiaramente non è mai stato testato:
running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do
echo Already locked
exit 6
fi
Ripariamo gli errori di sintassi e gli ps
argomenti rotti e otteniamo:
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
Questo script uscirà sempre 6, ogni volta, indipendentemente da come lo si esegue.
Se lo esegui ./myscript
, l' ps
output sarà 12345 -bash
, il che non corrisponde alla stringa richiesta 12345 bash ./myscript
, quindi fallirà.
Se lo esegui bash myscript
, le cose diventano più interessanti. Il processo bash richiede l'esecuzione della pipeline e la shell figlio esegue ps
e grep
. Sia la shell originale che la shell figlio verranno visualizzate ps
nell'output, in questo modo:
25793 bash myscript
25795 bash myscript
Non è l'output previsto $$ bash $0
, quindi lo script verrà chiuso.
Approccio rotto n. 2
Ora, in tutta onestà per l'utente che ha scritto l'approccio n. 1, ho fatto qualcosa di simile da solo quando ho provato questo:
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
Questo funziona quasi . Ma il fatto di biforcarsi per eseguire il tubo lo butta via. Quindi anche questo uscirà sempre.
Approccio n. 3 inaffidabile
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
Questa versione evita il problema di biforcazione della pipeline nell'approccio n. 2 ottenendo prima tutti i PID che hanno lo script corrente nei loro argomenti della riga di comando, quindi filtrando tale pidlist, separatamente, per omettere il PID dello script corrente.
Questo potrebbe funzionare ... a condizione che nessun altro processo abbia una riga di comando corrispondente a $0
, e se lo script viene sempre chiamato allo stesso modo (ad es. Se viene chiamato con un percorso relativo e quindi un percorso assoluto, quest'ultima istanza non noterà la prima ).
Approccio n. 4 inaffidabile
Quindi cosa succede se saltiamo il controllo dell'intera riga di comando, dal momento che potrebbe non indicare uno script effettivamente in esecuzione, e controlliamo lsof
invece di trovare tutti i processi che hanno questo script aperto?
Bene, sì, questo approccio in realtà non è poi così male:
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
Naturalmente, se è in esecuzione una copia dello script, la nuova istanza verrà avviata correttamente e avrai due copie in esecuzione.
O se lo script in esecuzione viene modificato (ad es. Con Vim o con a git checkout
), la "nuova" versione dello script si avvierà senza problemi, poiché sia Vim sia il git checkout
risultato in un nuovo file (un nuovo inode) al posto del vecchio.
Tuttavia, se lo script non viene mai modificato e mai copiato, questa versione è abbastanza buona. Non ci sono condizioni di competizione perché il file di script deve essere già aperto prima di poter raggiungere il controllo.
Possono esserci ancora falsi positivi se un altro processo ha il file di script aperto, ma nota che anche se è aperto per la modifica in Vim, vim in realtà non tiene aperto il file di script, quindi non genererà falsi positivi.
Ma ricorda, non usare questo approccio se lo script potrebbe essere modificato o copiato poiché otterrai falsi negativi, cioè più istanze in esecuzione contemporaneamente - quindi il fatto che la modifica con Vim non dia falsi positivi non dovrebbe importare a te. Ho parlato, però, perché l'approccio # 3 non dare falsi positivi (cioè si rifiuta di iniziare) se avete lo script aperto con Vim.
Quindi cosa fare, allora?
La risposta più votata a questa domanda offre un buon approccio solido.
Forse puoi scriverne uno migliore ... ma se non capisci tutti i problemi e le avvertenze con tutti gli approcci di cui sopra, non è probabile che tu scriva un metodo di blocco che li eviti tutti.
kill
ed; e sembra essere una buona pratica archiviare il proprio pid nel file di blocco, anziché semplicemente toccarlo.