189 votes

Un moyen rapide et efficace de s'assurer qu'une seule instance d'un shell script est en cours d'exécution à la fois.

Quel est le moyen le plus rapide de s'assurer qu'une seule instance d'un shell script est en cours d'exécution à un moment donné ?

13voto

Majal Mirasol Points 151

Vraiment rapide et vraiment sale ? Cette ligne unique en haut de votre script fonctionnera :

if [ `ps -e | grep -c $(basename $0)` -gt 2 ]; then exit 0; fi

Bien sûr, assurez-vous que le nom de votre script est unique. :)

5voto

Rob Points 31432

Créer un fichier de verrouillage dans un emplacement connu et vérifier son existence au démarrage de script ? Mettre le PID dans le fichier pourrait être utile si quelqu'un tente de retrouver une instance errante qui empêche l'exécution du script.

4voto

Jason Weathered Points 5346

En ciblant une machine Debian, je trouve le lockfile-progs pour être une bonne solution. procmail est également accompagné d'un lockfile outil. Cependant, il m'arrive parfois de n'avoir ni l'un ni l'autre.

Voici ma solution qui utilise mkdir pour l'atomicité et un fichier PID pour détecter les verrous périmés. Ce code est actuellement en production sur une installation Cygwin et fonctionne bien.

Pour l'utiliser, il suffit d'appeler exclusive_lock_require quand vous avez besoin d'un accès exclusif à quelque chose. Un paramètre facultatif de nom de verrou vous permet de partager les verrous entre différents scripts. Il existe également deux fonctions de niveau inférieur ( exclusive_lock_try y exclusive_lock_retry ) si vous avez besoin de quelque chose de plus complexe.

function exclusive_lock_try() # [lockname]
{

    local LOCK_NAME="${1:-`basename $0`}"

    LOCK_DIR="/tmp/.${LOCK_NAME}.lock"
    local LOCK_PID_FILE="${LOCK_DIR}/${LOCK_NAME}.pid"

    if [ -e "$LOCK_DIR" ]
    then
        local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
        if [ ! -z "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2> /dev/null
        then
            # locked by non-dead process
            echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
            return 1
        else
            # orphaned lock, take it over
            ( echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null && local LOCK_PID="$$"
        fi
    fi
    if [ "`trap -p EXIT`" != "" ]
    then
        # already have an EXIT trap
        echo "Cannot get lock, already have an EXIT trap"
        return 1
    fi
    if [ "$LOCK_PID" != "$$" ] &&
        ! ( umask 077 && mkdir "$LOCK_DIR" && umask 177 && echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null
    then
        local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
        # unable to acquire lock, new process got in first
        echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
        return 1
    fi
    trap "/bin/rm -rf \"$LOCK_DIR\"; exit;" EXIT

    return 0 # got lock

}

function exclusive_lock_retry() # [lockname] [retries] [delay]
{

    local LOCK_NAME="$1"
    local MAX_TRIES="${2:-5}"
    local DELAY="${3:-2}"

    local TRIES=0
    local LOCK_RETVAL

    while [ "$TRIES" -lt "$MAX_TRIES" ]
    do

        if [ "$TRIES" -gt 0 ]
        then
            sleep "$DELAY"
        fi
        local TRIES=$(( $TRIES + 1 ))

        if [ "$TRIES" -lt "$MAX_TRIES" ]
        then
            exclusive_lock_try "$LOCK_NAME" > /dev/null
        else
            exclusive_lock_try "$LOCK_NAME"
        fi
        LOCK_RETVAL="${PIPESTATUS[0]}"

        if [ "$LOCK_RETVAL" -eq 0 ]
        then
            return 0
        fi

    done

    return "$LOCK_RETVAL"

}

function exclusive_lock_require() # [lockname] [retries] [delay]
{
    if ! exclusive_lock_retry "$@"
    then
        exit 1
    fi
}

4voto

presto8 Points 173

Si les limitations de flock, qui ont déjà été décrites ailleurs dans ce fil, ne sont pas un problème pour vous, alors cela devrait fonctionner :

#!/bin/bash

{
    # exit if we are unable to obtain a lock; this would happen if 
    # the script is already running elsewhere
    flock -x -n 100 || exit

    # put commands to run here
    sleep 100
} 100>/tmp/myjob.lock

3voto

dmckee Points 50318

Certains unixes ont lockfile qui est très similaire à celui déjà mentionné flock .

De la page de manuel :

lockfile peut être utilisé pour créer un ou plusieurs fichiers sémaphores. Si lock- file ne peut pas créer tous les fichiers fichiers spécifiés (dans l'ordre spécifié), il attend le temps de sommeil (par défaut 8) secondes et tente à nouveau le dernier fichier qui qui n'a pas réussi. Vous pouvez spécifier le nombre de tentatives à effectuer jusqu'à ce que l'échec soit retourné. Si le nombre de de tentatives est -1 (par défaut, c'est-à-dire -r-1), lockfile essaiera indéfiniment.

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