Pour une utilisation réelle, vous devez utiliser la réponse la plus votée .
Cependant, je souhaite aborder diverses approches brisées et semi-exploitables, ps
ainsi que leurs nombreuses mises en garde, car je constate que de nombreuses personnes les utilisent.
Cette réponse est vraiment la réponse à "Pourquoi ne pas utiliser ps
et grep
gérer le verrouillage dans la coque?"
Approche brisée # 1
Premièrement, une approche donnée dans une autre réponse qui a eu quelques votes positifs malgré le fait que cela ne fonctionnait pas (et ne pourrait jamais) et n’avait clairement jamais été testée:
running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do
echo Already locked
exit 6
fi
Corrigeons les erreurs de syntaxe et les ps
arguments cassés et obtenons:
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
Ce script quittera toujours 6 à chaque fois, quelle que soit la manière dont vous l'exécutez.
Si vous l'exécutez avec ./myscript
, la ps
sortie sera simplement 12345 -bash
, ce qui ne correspond pas à la chaîne requise 12345 bash ./myscript
, donc cela échouera.
Si vous le lancez avec bash myscript
, les choses deviennent plus intéressantes. Le processus bash fourches pour exécuter le pipeline, et l' enfant shell court le ps
et grep
. Le shell original et le shell enfant apparaîtront dans la ps
sortie, comme ceci:
25793 bash myscript
25795 bash myscript
Ce n'est pas la sortie attendue $$ bash $0
, votre script va donc se fermer.
Approche brisée # 2
Maintenant, en toute justice pour l'utilisateur qui a écrit l'approche cassée n ° 1, j'ai fait quelque chose de similaire moi-même lorsque j'ai essayé pour la première fois:
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
Cela fonctionne presque . Mais le fait de forcer pour faire fonctionner le tuyau jette cela au large. Donc, celui-ci sortira toujours, aussi.
Approche peu fiable n ° 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
Cette version évite le problème de forçage de pipeline dans l'approche n ° 2 en obtenant d'abord tous les PID qui ont le script actuel dans leurs arguments de ligne de commande, puis en filtrant cette pidlist, séparément, pour omettre le PID du script actuel.
Cela pourrait fonctionner ... à condition qu'aucun autre processus n'ait une ligne de commande correspondant à l'élément $0
et que le script soit toujours appelé de la même manière (par exemple, s'il est appelé avec un chemin relatif puis un chemin absolu, la dernière instance ne remarquera pas le premier. )
Approche peu fiable n ° 4
Alors, que se passe-t-il si nous omettons de vérifier la ligne de commande complète, car cela n’indiquera peut-être pas un script en cours d’exécution, et lsof
rechercherons à la place tous les processus pour lesquels ce script est ouvert?
Eh bien, oui, cette approche n’est pas si mauvaise en réalité:
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
Bien sûr, si une copie du script est en cours d'exécution, la nouvelle instance démarrera correctement et vous aurez deux copies en cours d'exécution.
Ou si le script en cours d'exécution est modifié (par exemple avec Vim ou avec a git checkout
), la "nouvelle" version du script démarrera sans problème, car Vim et le git checkout
résultat, un nouveau fichier (un nouvel inode) à la place du fichier le vieux.
Cependant, si le script n'est jamais modifié ni copié, cette version est plutôt bonne. Il n'y a pas de condition de concurrence, car le fichier de script doit déjà être ouvert avant que le contrôle puisse être atteint.
Il peut toujours y avoir des faux positifs si le fichier de script est ouvert par un autre processus, mais notez que même s'il est ouvert à l'édition dans Vim, vim ne tient pas le fichier de script ouvert et ne génère pas de faux positifs.
Mais rappelez-vous, n'utilisez pas cette approche si le script peut être édité ou copié car vous obtiendrez de faux négatifs, c'est-à-dire plusieurs instances s'exécutant en même temps. Le fait que l'édition avec Vim ne génère pas de faux positifs ne devrait donc pas avoir d'importance. à toi. Je le mentionne cependant car l'approche n ° 3 ne donne de faux positifs (c. -à- refuse de démarrer) si vous avez le script ouvert avec Vim.
Alors que faire, alors?
La réponse la plus votée à cette question donne une bonne approche solide.
Peut-être pourriez-vous en écrire un meilleur ... mais si vous ne comprenez pas tous les problèmes et toutes les mises en garde concernant toutes les approches ci-dessus, il est peu probable que vous écriviez une méthode de verrouillage qui les évite toutes.
kill
édité; et il semble être une bonne pratique de stocker son propre pid dans le fichier verrou plutôt que de le toucher.