Bash moyen de vérifier si un processus est déjà en cours d'exécution en arrière-plan (et ignorer la réexécution en fonction de cela)?

11

Puis-je créer une ligne de commande bash qui n'exécute qu'une certaine commande si le processus n'est pas déjà en cours d'exécution (en arrière-plan)?

Comment vérifier * si une commande est déjà en cours d'exécution?

(afin que je puisse ajouter la commande suivante &&entre eux afin que la suivante s'exécute uniquement si la première est vraie).

*: tester, déterminer, découvrir, découvrir

n611x007
la source
3
ps -ef | grep -v grep | grep "process_name" || run_command_here
Rahul Patil
1
@RahulPatil vous pouvez utiliser juste pgrep "process_name"au lieu deps | grep | grep
précipitez-vous le
hmm, j'oublie que ..: D
Rahul Patil
1
Pourquoi n'utilisez-vous pas un fichier "verrou", et lorsque vous lancez la deuxième fois, il ne se lancera que lorsque le fichier verrou disparaîtra.
BitsOfNix
meilleure façon de vérifier si un processus existe: stackoverflow.com/questions/3043978/…
Trevor Boyd Smith

Réponses:

3

J'ai utilisé cette technique de temps en temps:

$ pgrep <process name> || <process name>

Avant pgrepcela se faisait de cette façon:

$ ps -eaf | grep -q <[p]rocess name> || <process name>

exemple

Le bit avec le [p]fait en sorte que le grepne se retrouve pas en conséquence.

$ ps -eaf | grep -q [s]leep || sleep 10
slm
la source
2

Cela peut être délicat, car vous pouvez avoir des instances distinctes du même processus qui vivent indépendamment. Par exemple, des serveurs écoutant sur différents ports ou des services fonctionnant sous différents utilisateurs. Afin de faire la distinction entre ces instances, vous devez attribuer à chacune d'entre elles une balise unique. La balise est souvent un fichier, mais elle peut être une socket locale dans l'espace de noms abstrait, un port TCP, etc. - n'importe quel identifiant unique fera l'affaire. Lorsque la balise est un fichier, il peut s'agir d'un fichier standard contenant un ID de processus (un pidfile), ou un canal ou socket nommé que le fichier écoute, etc. Idéalement, la balise est un point de terminaison de communication qui permet aux clients de se connecter à ce processus.

Chacun de ces différents types de balises entraîne une manière différente de vérifier si l'instance que vous recherchez est opérationnelle. Par exemple, avec un socket de fichier local, essayez de vous y connecter et démarrez le processus s'il n'y a pas de processus d'écoute sur ce socket. Si la balise est un fichier pid, vérifiez s'il existe un processus avec cet ID de processus, mais attention à ce qu'il soit fragile, car si le processus est mort, il peut y avoir un processus indépendant qui a réutilisé son ID. Gardez à l'esprit que si deux clients tentent d'atteindre le processus dans un court laps de temps, ils pourraient tous deux constater que le processus n'existe pas et tous les deux tenter de le démarrer; une protection adéquate contre cette condition de concurrence peut être délicate.

Il est plus facile de gérer les instances lorsqu'elles sont toutes démarrées par le même processus de superviseur, et ce processus de superviseur détecte quand les instances meurent et réagit en conséquence. De nombreux programmes de surveillance des services peuvent le faire.

Si le programme ne répond pas sur un point de terminaison de communication connu et qu'il n'est pas géré par un programme superviseur, la balise du pauvre est un fichier pid: un fichier contenant l'ID du processus. Lorsque vous démarrez le processus, écrivez le pid dans un fichier avec un nom préarrangé. Lorsque vous avez besoin que le processus existe, lisez le fichier pid et voyez s'il existe un processus avec ce pid. Lorsque vous tuez le processus, effacez le fichier pid. Le problème le plus important avec un fichier pid non supervisé est que si le processus meurt, son pid peut être réutilisé par un processus non lié. Vous devez au moins vérifier le nom du processus ou l'exécutable du processus pour vous assurer que vous parlez au bon processus. De nombreuses variantes Unix ont une commande pgrep :pgrep SOMENAME répertorie les processus dont le nom contient SOMENAME en tant que sous-chaîne, avec des options supplémentaires pour limiter à un utilisateur particulier, pour exiger une correspondance exacte, pour changer laquelle des différentes notions possibles de «nom de processus» est utilisée, etc.

Gilles 'SO- arrête d'être méchant'
la source
1

Vous pouvez utiliser cette approche:

if [[ -z $(ps -C appname -opid=) ]]; then
    appname && secondapp
fi
jasonwryan
la source
1

Autres options:

  • pgrep -xq processname
    • Correspond uniquement aux 15 premiers caractères de GNU / Linux
    • N'inclut pas les ancêtres sur OS X
  • ps -eo comm= | sed 's|.*/||' | grep -xq processname
    • Correspond uniquement aux 15 premiers caractères de GNU / Linux
    • sed 's|.*/||' supprime les parties dirname sous OS X

Sous GNU / Linux, les ps -o commnoms de commande sont tronqués à 15 caractères pgrepet ps -Cne correspondent qu'aux 15 premiers caractères.

ps -C (correspondre aux noms de commande) n'est pas pris en charge sous OS X.

Sous OS X, ps -o commimprime les chemins absolus des commandes et ps -co commn'imprime que les noms des commandes. Dans GNU, ps -o commimprime uniquement les noms de commandes et -ca une signification différente.

Pgrep d'OS X n'inclut pas les processus ancêtres (comme bash, Terminal ou launchd) sans -a. Pgrep de GNU les inclut par défaut et il ne les prend pas en charge -a.

grep -xet pgrep -xn'implique pas -F, donc utilisez -Fxsi le nom du processus peut contenir des caractères regex.

Lri
la source
-C n'est pas disponible sur mon cygwin non plus :)
n611x007
1

Je suis désolé mais toutes ces solutions ne prennent pas en charge contab car la même ligne de commande apparaîtra deux fois dans le résultat 'ps'.

Voici donc le mien:

## Test pour voir si le même script tourne déjà
## Un fichier .pid est utilisé pour stocké le numéro de process
## Si le pid est en train de tourner alors on sort.
lock_file=$0".pid"
[ -r $lock_file ] && read pid <$lock_file
if [ "$pid" -gt 1 ] && [ `ps --no-headers -p "$pid" | wc -l` -gt 0 ] ; then
    echo "WARNING : le process $pid tourne deja : $0"
    ps -edf | grep `basename $0` | grep -v grep
    echo "WARNING : Arrêt de cette instance ($$)."
    exit 7
fi
echo $$ >$lock_file
Francis
la source
De quoi êtes-vous désolé? Qu'est-ce que le contab? Voulez-vous dire vérifier à partir d'un cronemploi?
Anthon
0

Avec Bash

#!/usr/bin/env bash

[[ $# -eq 0 ]] && { echo -e "Usage:\t\t $0 <Process_name>  <Command here>"; exit 1;  }

ifnotrun(){
        local p=$1
        if ! ps -C "$1" -opid=
        then
                cmd=($@)
                echo ${cmd[@]:1}
        else
                echo "Process \"$p\" Already Running.."
                exit 1
        fi

}

ifnotrun $*

Remarque: - supprimez echosi la sortie semble correcte.

Rahul Patil
la source
0

Je vais vous expliquer le cas où vous exécutez la commande dans beckgreoud. Le "$!" enregistrer le PID du dernier processus d'arrière-plan. Ainsi, vous pouvez l'utiliser pour le trouver dans les tableaux de processus suivant les réponses ci-dessus:

sleep 4 &
ps -ef | grep -w  $!  ...

La commande intégrée "jobs" - essayez ceci:

sleep 4&
J=`jobs`
while [ "$J" ]; do
        sleep 1
        jobs # This line flush the jobs' bufer.
        J=`jobs`
done

Concernant l'option "&&"

Au lieu de &&, utilisez la commande wait. Dans l'exemple suivant, myproc2 ne s'exécutera pas tant que myproc1 n'aura pas terminé:

myproc1 &
wait
myproc2
Udi
la source
0

Obtenez l'état de votre processus:

ps -lp $(pgrep <YOUR_PROCESS_NAME>) | tail -1 | awk '{print $11}'

Référence:

D    uninterruptible sleep (usually IO)
R    running or runnable (on run queue)
S    interruptible sleep (waiting for an event to complete)
T    stopped, either by a job control signal or because it is being traced
W    paging (not valid since the 2.6.xx kernel)
X    dead (should never be seen)
Z    defunct ("zombie") process, terminated but not reaped by its parent

Par exemple, je l'ai utilisé pour jouer ou suspendre conditionnellement mon processus sox sur une session tmux:

/usr/local/bin/tmux if-shell -t sox "[ $(ps -lp $(pgrep sox) | tail -1 | awk '{print $11}') == 'T' ]" \
  'send -t sox "fg" Enter' \
  'send -t sox C-z'
Jose Alban
la source
-1

Vous pouvez l'utiliser dans un script:

if [ `ps -ef | grep "script.sh" | grep -v grep | wc -l` -gt 1 ] ; then
echo "RUNNING...."
else
echo "NOT RUNNING..."
fi
Pravs
la source