138 votes

Quel est le meilleur moyen de s'assurer qu'une seule instance d'un script Bash est en cours d'exécution ?

Quel est le moyen le plus simple/le plus efficace de s'assurer qu'une seule instance d'un script donné est en cours d'exécution - en supposant qu'il s'agisse de Bash sur Linux ?

En ce moment, je le fais :

ps -C script.name.sh > /dev/null 2>&1 || ./script.name.sh

mais il présente plusieurs problèmes :

  1. il met la vérification en dehors de script
  2. il ne me laisse pas exécuter le même script à partir de comptes séparés - ce que j'aimerais parfois.
  3. -C vérifie uniquement les 14 premiers caractères du nom du processus

Bien sûr, je peux écrire ma propre gestion du fichier pidfile, mais je sens qu'il devrait y avoir un moyen simple de le faire.

3voto

yy.w Points 1

premier exemple de test

[[ $(lsof -t $0| wc -l) > 1 ]] && echo "At least one of $0 is running"

deuxième exemple de test

currsh=$0
currpid=$$
runpid=$(lsof -t $currsh| paste -s -d " ")
if [[ $runpid == $currpid ]]
then
  sleep 11111111111111111
else
  echo -e "\nPID($runpid)($currpid) ::: At least one of \"$currsh\" is running !!!\n"
  false
  exit 1
fi

explication

"lsof -t" pour lister tous les pids des scripts en cours d'exécution nommés "$0".

La commande "lsof" présente deux avantages.

  1. Ignorez les pids qui sont édités par un éditeur tel que vim, parce que vim édite son fichier de correspondance tel que ".file.swp".
  2. Ignore les pids forkés par le shell courant scripts, ce que la plupart des commandes dérivées de "grep" ne peuvent pas faire. Utilisez la commande "pstree -pH pidnum" pour voir les détails sur le statut de bifurcation du processus en cours.

2voto

laust.rud Points 388

Je vous recommande également de regarder chpst (partie de runit) :

chpst -L /tmp/your-lockfile.loc ./script.name.sh

1voto

Noah Spurrier Points 339

Les distributions Ubuntu/Debian disposent de l'option start-stop-daemon qui a le même but que celui que vous décrivez. Voir aussi /etc/init.d/skeleton pour voir comment il est utilisé dans l'écriture de scripts de démarrage/arrêt.

-- Noah

0voto

Dm1 Points 1

Solution ultime en une seule ligne :

[ "$(pgrep -fn $0)" -ne "$(pgrep -fo $0)" ] && echo "At least 2 copies of $0 are running"

0voto

Erik Lundmark Points 11

J'ai eu le même problème, et j'ai trouvé un modèle qui utilise lockfile, un fichier pid qui contient le numéro d'identification du processus, et un fichier kill -0 $(cat $pid_file) vérification pour que les scripts avortés n'arrêtent pas l'exécution suivante. Cela crée un dossier foobar-$USERID dans /tmp où se trouve le fichier lockfile et le fichier pid.

Vous pouvez encore appeler le script et faire d'autres choses, tant que vous gardez ces actions dans alertRunningPS .

#!/bin/bash

user_id_num=$(id -u)
pid_file="/tmp/foobar-$user_id_num/foobar-$user_id_num.pid"
lock_file="/tmp/foobar-$user_id_num/running.lock"
ps_id=$$

function alertRunningPS () {
    local PID=$(cat "$pid_file" 2> /dev/null)
    echo "Lockfile present. ps id file: $PID"
    echo "Checking if process is actually running or something left over from crash..."
    if kill -0 $PID 2> /dev/null; then
        echo "Already running, exiting"
        exit 1
    else
        echo "Not running, removing lock and continuing"
        rm -f "$lock_file"
        lockfile -r 0 "$lock_file"
    fi
}

echo "Hello, checking some stuff before locking stuff"

# Lock further operations to one process
mkdir -p /tmp/foobar-$user_id_num
lockfile -r 0 "$lock_file" || alertRunningPS

# Do stuff here
echo -n $ps_id > "$pid_file"
echo "Running stuff in ONE ps"

sleep 30s

rm -f "$lock_file"
rm -f "$pid_file"
exit 0

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X