web-dev-qa-db-fra.com

Comment vérifier si une autre instance de mon script Shell est en cours d'exécution

GNU bash, version 1.14.7 (1)

J'ai un script qui s'appelle "abc.sh" Je dois vérifier ceci à partir du script abc.sh uniquement ... À l'intérieur, j'ai écrit la déclaration suivante.

status=`ps -efww | grep -w "abc.sh" | grep -v grep | grep -v $$ | awk '{ print $2 }'`
if [ ! -z "$status" ]; then
        echo "[`date`] : abc.sh : Process is already running"
        exit 1;
fi

Je sais que c'est faux, car chaque fois qu'il se termine car il trouve son propre processus dans 'ps' Comment le résoudre? Comment puis-je vérifier que le script est déjà en cours d'exécution ou pas uniquement from that script?

25
Jatin Bodarya

Un moyen plus facile de vérifier si un processus est déjà en cours d'exécution est la commande pidof.

if pidof -x "abc.sh" >/dev/null; then
    echo "Process already running"
fi

Vous pouvez également demander à votre script de créer un fichier PID lors de son exécution. C'est ensuite un simple exercice de vérification de la présence du fichier PID pour déterminer si le processus est déjà en cours d'exécution.

#!/bin/bash
# abc.sh

mypidfile=/var/run/abc.sh.pid

# Could add check for existence of mypidfile here if interlock is
# needed in the Shell script itself.

# Ensure PID file is removed on program exit.
trap "rm -f -- '$mypidfile'" EXIT

# Create a file with current PID to indicate that process is running.
echo $$ > "$mypidfile"

...

Mise à jour: La question a maintenant changé pour vérifier à partir du script lui-même. Dans ce cas, nous nous attendons à toujours voir au moins un abc.sh en cours d'exécution. S'il existe plus d'un abc.sh, nous savons que ce processus est toujours en cours d'exécution. Je suggérerais quand même d'utiliser la commande pidof qui renverrait 2 PID si le processus était déjà en cours d'exécution. Vous pouvez utiliser grep pour filtrer le PID actuel, la boucle dans le shell ou même revenir au comptage des PID avec wc pour détecter plusieurs processus. 

Voici un exemple:

#!/bin/bash

for pid in $(pidof -x abc.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : abc.sh : Process is already running with PID $pid"
        exit 1
    fi
done
43
Austin Phillips

Si vous voulez la méthode "pidof", voici le truc:

    if pidof -o %PPID -x "abc.sh">/dev/null; then
        echo "Process already running"
    fi

Où le paramètre -o %PPID indique d'omettre le pid du shell ou du script shell appelant. Plus d'informations dans la page de manuel pidof.

19
Aba

Voici un truc que vous verrez à différents endroits:

status=`ps -efww | grep -w "[a]bc.sh" | awk -vpid=$$ '$2 != pid { print $2 }'`
if [ ! -z "$status" ]; then
    echo "[`date`] : abc.sh : Process is already running"
    exit 1;
fi

Les crochets entourant le [a] (ou choisissez une lettre différente) empêchent grep de se retrouver. Cela rend le bit grep -v grep inutile. J'ai également supprimé le grep -v $$ et corrigé la partie awk pour accomplir la même chose.

10
twalberg

Quelqu'un s'il vous plaît abattez-moi si je me trompe ici

Je comprends que l’opération mkdir est atomique, vous pouvez donc créer un verrou répertoire

#!/bin/sh
lockdir=/tmp/AXgqg0lsoeykp9L9NZjIuaqvu7ANILL4foeqzpJcTs3YkwtiJ0
mkdir $lockdir  || {
    echo "lock directory exists. exiting"
    exit 1
}
# take pains to remove lock directory when script terminates
trap "rmdir $lockdir" EXIT INT KILL TERM

# rest of script here
6
glenn jackman

Utilisez la commande PS de manière légèrement différente pour ignorer également le processus enfant:

ps -eaf | grep -v grep | grep $PROCESS | grep -v $$
3
Sridhar Kumar N

pidof ne fonctionnait pas pour moi, alors j'ai cherché un peu plus et je suis tombé sur pgrep

for pid in $(pgrep -f my_script.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : my_script.sh : Process is already running with PID $pid"
        exit 1
    else
      echo "Running with PID $pid"
    fi  
done

Extrait des réponses ci-dessus et/ https://askubuntu.com/a/803106/802276

2
Scott H

Je crée un fichier temporaire en cours d'exécution.

Voici comment je le fais:

#!/bin/sh
# check if lock file exists
if [ -e /tmp/script.lock ]; then
  echo "script is already running"
else
# create a lock file
  touch /tmp/script.lock
  echo "run script..."
#remove lock file
 rm /tmp/script.lock
fi
2
Cleber Reizen

Je ne voulais pas coder en dur abc.sh dans la vérification, alors j'ai utilisé ce qui suit:

MY_SCRIPT_NAME=`basename "$0"`
if pidof -o %PPID -x $MY_SCRIPT_NAME > /dev/null; then
    echo "$MY_SCRIPT_NAME already running; exiting"
    exit 1
fi
1
gorus

Voici comment je le fais dans un script bash:

if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
    echo "The script is already running."
    exit 1
fi

Cela me permet d’utiliser cet extrait pour n’importe quel script bash. J'avais besoin de grep bash, car lors de son utilisation avec cron, il crée un autre processus qui l'exécute avec/bin/sh.

1
CM Cruz

J'ai constaté qu'en utilisant des pseudonymes pour capturer le résultat d'une commande dans une variable, il en résulte un nombre trop élevé de ps aux results, par exemple pour une seule instance en cours d'exécution de abc.sh :

ps aux | grep -w "abc.sh" | grep -v grep | wc -l

renvoie "1". cependant,

count=`ps aux | grep -w "abc.sh" | grep -v grep | wc -l`
echo $count

renvoie "2"

On dirait que l'utilisation de la construction backtick crée temporairement un autre processus. Cela pourrait être la raison pour laquelle le sujet ne pourrait pas faire ce travail. Juste besoin de décrémenter le $ count var.

1
Jimmy Falcon

Je trouve que la réponse de @Austin Phillips est parfaite. Une petite amélioration que je ferais est d'ajouter -o (pour ignorer le pid du script lui-même) et de faire correspondre le script avec le nom de base (c'est-à-dire que le même code peut être placé dans n'importe quel script):

if pidof -x "`basename $0`" -o $$ >/dev/null; then
    echo "Process already running"
fi
0
Andrei Neagoe