Commande Linux / Unix pour déterminer si le processus est en cours d'exécution?

97

J'ai besoin d'une commande shell / bash indépendante de la plate-forme (Linux / Unix | OSX) qui déterminera si un processus spécifique est en cours d'exécution. par exemple mysqld, httpd... Quelle est la manière / commande la plus simple de faire cela?

Autoroute de la vie
la source

Réponses:

168

Bien que pidofet pgrepsoient d'excellents outils pour déterminer ce qui fonctionne, ils ne sont malheureusement pas disponibles sur certains systèmes d'exploitation. Une sécurité intégrée définitive serait d'utiliser ce qui suit:ps cax | grep command

La sortie sur Gentoo Linux:

14484? S 0:00 apache2
14667? S 0:00 apache2
19620? Sl 0:00 apache2
21132? Ss 0:04 apache2

La sortie sur OS X:

42582 ?? Z 0: 00.00 (smbclient)
46529 ?? Z 0: 00.00 (smbclient)
46539 ?? Z 0: 00.00 (smbclient)
46547 ?? Z 0: 00.00 (smbclient)
46586 ?? Z 0: 00.00 (smbclient)
46594 ?? Z 0: 00.00 (smbclient)

Sur Linux et OS X, grep renvoie un code de sortie, il est donc facile de vérifier si le processus a été trouvé ou non:

#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

De plus, si vous souhaitez la liste des PID, vous pouvez facilement grep pour ceux-ci également:

ps cax | grep httpd | grep -o '^ [] * [0-9] *'

Dont la sortie est la même sous Linux et OS X:

3519 3521 3523 3524

La sortie de ce qui suit est une chaîne vide, ce qui rend cette approche sûre pour les processus qui ne sont pas en cours d'exécution:

écho ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'

Cette approche convient pour écrire un simple test de chaîne vide, puis même pour parcourir les PID découverts.

#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
  echo "Process not running." 1>&2
  exit 1
else
  for PID in $PIDS; do
    echo $PID
  done
fi

Vous pouvez le tester en l'enregistrant dans un fichier (nommé "running") avec des droits d'exécution (chmod + x running) et en l'exécutant avec un paramètre: ./running "httpd"

#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

AVERTISSEMENT!!!

Veuillez garder à l'esprit que vous analysez simplement la sortie, ps axce qui signifie que, comme on le voit dans la sortie Linux, il ne s'agit pas simplement d'une correspondance sur les processus, mais aussi sur les arguments passés à ce programme. Je recommande fortement d'être aussi précis que possible lors de l'utilisation de cette méthode (par exemple ./running "mysql", correspondra également aux processus «mysqld»). Je recommande fortement d'utiliser whichpour vérifier par rapport à un chemin complet lorsque cela est possible.


Références:

http://linux.about.com/od/commands/l/blcmdl1_ps.htm

http://linux.about.com/od/commands/l/blcmdl1_grep.htm

Gris Caleb
la source
Le processus peut être en cours d'exécution, mais arrêté. Donc, si le but est de tester si mysqld ou httpd sont "opérationnels" (en réponse), vous devez également vérifier s'il est arrêté ou non.
oluc
2
Désolé, mais bien que la réponse soit certainement juste d'un point de vue sémantique, je suis totalement contre d'essayer de trouver un processus par correspondance de motifs sur le vecteur arg du processus. Une telle approche est vouée à l'échec tôt ou tard (vous l'admettez vous-même, en disant que d'autres contrôles sont nécessaires). J'ai ajouté ma propre recommandation dans une réponse distincte.
peterh
6
grepse trouvera également en cours d'exécution (par exemple ps cax | grep randomname, retournera toujours 0 parce que greptrouve grep randomname(j'espère que c'est clair ...). Une solution consiste à ajouter des crochets autour de la première lettre du nom du processus, par exemple ps cax | grep [r]andomname.
Kyle G.
ps cax | rev | cut -f1 -d' ' | revaffichera uniquement la colonne de nom, pour une analyse plus facile.
Tyzoid
1
ps caxne peut pas afficher entièrement le nom de la commande. Par exemple, il imprime "chrome-parcourir" au lieu de "chrome-browser".
jarno
24

Vous DEVRIEZ connaître le PID!

Trouver un processus en essayant de faire une sorte de reconnaissance de formes sur les arguments du processus (comme pgrep "mysqld") est une stratégie vouée à l'échec tôt ou tard. Et si vous avez deux mysqld en cours d'exécution? Oubliez cette approche. Vous pouvez faire les choses temporairement et cela peut fonctionner pendant un an ou deux, mais il se passe alors quelque chose auquel vous n'avez pas pensé.

Seul l'identifiant de processus (pid) est vraiment unique.

Stockez toujours le pid lorsque vous lancez quelque chose en arrière-plan. Dans Bash, cela peut être fait avec la $!variable Bash. Vous vous épargnerez tellement de problèmes en le faisant.

Comment déterminer si le processus est en cours d'exécution (par pid)

Alors maintenant, la question est de savoir comment savoir si un pid est en cours d'exécution.

Faites simplement:

ps -o pid = -p <pid>

C'est POSIX et donc portable. Il renverra le pid lui-même si le processus est en cours d'exécution ou ne retournera rien si le processus n'est pas en cours d'exécution. À proprement parler, la commande renverra une seule colonne, le pid, mais puisque nous avons donné qu'un en-tête de titre vide (le truc précédant immédiatement le signe égal) et que c'est la seule colonne demandée, la commande ps n'utilisera pas du tout l'en-tête. C'est ce que nous voulons car cela facilite l'analyse.

Cela fonctionnera sous Linux, BSD, Solaris, etc.

Une autre stratégie consisterait à tester la valeur de sortie de la pscommande ci-dessus . Il doit être nul si le processus est en cours d'exécution et différent de zéro si ce n'est pas le cas. La spécification POSIX dit que psdoit quitter> 0 si une erreur s'est produite, mais je ne sais pas ce qui constitue «une erreur». Par conséquent, je n'utilise pas personnellement cette stratégie bien que je sois presque sûr qu'elle fonctionnera également sur toutes les plates-formes Unix / Linux.

Peterh
la source
1
Sauf que cela ne répond pas à la question, qui consiste à déterminer si un service est en cours d'exécution. Le PID ne sera pas connu dans ce cas, par conséquent , cette réponse est valable uniquement si vous faites connaître le PID.
Highway of Life
2
Faux. Tout mon propos du commentaire est de prendre du recul et de dire que si vous vous trouvez d'abord dans une situation où vous devez faire une sorte de grep <sometext>recherche d'un processus donné, vous avez fait quelque chose de mal lorsque vous avez commencé le processus, à mon humble avis. Je déduis de la question du PO qu'effectivement il a le contrôle sur la façon dont le processus est lancé.
peterh
2
Le "terme" plus correct pour la question OP aurait dû être "commande multiplateforme pour déterminer si un service est en cours d'exécution", ce n'est pas le même système qui exécute la vérification, mais un système extérieur, donc le PID ne sera tout simplement pas connu du tout.
Highway of Life
2
Ce n'est pas infaillible. Le processus qui vous intéresse peut être mort après que le système ait été suffisamment longtemps en service pour que les PID se terminent, et un autre processus peut alors avoir reçu le même PID que vous vérifiez. stackoverflow.com/questions/11323410/linux-pid-recycling
claymation
1
@claymation. Bon point. Cependant, la méthode PID est toujours meilleure que la correspondance de modèles sur les arguments de processus, car un conflit PID est beaucoup plus improbable que le démarrage accidentel de deux instances du même service. Juste mes deux cents. :-)
peterh
15

Sur la plupart des distributions Linux, vous pouvez utiliser pidof(8).

Il imprimera les ID de processus de toutes les instances en cours d'exécution des processus spécifiés, ou rien si aucune instance n'est en cours d'exécution.

Par exemple, sur mon système (j'ai quatre instances de bashet une instance de remminafonctionnement):

$ pidof bash remmina
6148 6147 6144 5603 21598

Sur d'autres Unices, pgrepou une combinaison de pset grepréalisera la même chose, comme d'autres l'ont souligné à juste titre.

Frédéric Hamidi
la source
+1 pidof httpdfonctionne bien sur Red Hat 5. Mais sur mon Red Hat 4, pidofn'est pas présent :-(
olibre
En effet, cette commande est moins répandue que je ne le pensais, j'ai édité ma réponse pour que cela soit plus clair.
Frédéric Hamidi
Belle réponse propre en effet. (sur les systèmes pris en charge). Je vous remercie.
Mtl Dev
7

Cela devrait fonctionner sur la plupart des versions d'Unix, BSD et Linux:

PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep

Testé sur:

  • SunOS 5.10 [D'où le PATH=...]
  • Linux 2.6.32 (CentOS)
  • Linux 3.0.0 (Ubuntu)
  • Darwin 11.2.0
  • FreeBSD 9.0-STABLE
  • Red Hat Enterprise Linux ES version 4
  • Red Hat Enterprise Linux Server version 5
Johnsyweb
la source
2
+1 Oui simplement ps. Pour éviter la seconde grepje suggère:ps aux | grep [h]ttpd
olibre
Je n'ai pas utilisé l'astuce du crochet carré ici pour faciliter la mise d'une variable dans le main grep.
Johnsyweb
1
Très bien;) Je viens de tester sur Red Hat AS 4 et Red Hat AP 5. Bien sûr que je travaille! Vous pouvez donc ajouter à votre liste: Red Hat Enterprise Linux ES version 4 et Red Hat Enterprise Linux Server version 5 . Cheers
olibre
@Downvoter: Pourquoi? Qu'est-ce que j'ai raté? Pour autant que je sache, la réponse acceptée est de faire la même recherche!
Johnsyweb
6

Le moyen le plus simple est d'utiliser ps et grep:

command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
    echo "Command is running"
else
    echo "Command is not running"
fi

Si votre commande a des arguments de commande, vous pouvez également mettre plus de «grep cmd_arg1» après «grep $ command» pour filtrer les autres processus possibles qui ne vous intéressent pas.

Exemple: montrez-moi si un processus java avec l'argument fourni:

-Djava.util.logging.config.file = logging.properties

est en cours d'exécution

ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l
Pawel Solarski
la source
2
En fait, l'utilisation ps caxélimine le besoin d'utiliser grep -v. Ainsi , par exemple, vous pouvez utiliser: ps cax | grep java > /dev/null || echo "Java not running".
Highway of Life
1
Il y a une erreur en 3e ligne. veuillez changer "en cours d'exécution" en "$ en cours d'exécution".
Programmeur
5

Juste un ajout mineur: si vous ajoutez le -cdrapeau à ps, vous n'avez pas besoin de supprimer la ligne contenant le processus grep avec grep -vpar la suite. C'est à dire

ps acux | grep cron

est tout ce dont vous aurez besoin sur un système bsd-ish (cela inclut MacOSX) Vous pouvez laisser le -u côté si vous avez besoin de moins d'informations.

Sur un système où la génétique de la pscommande native renvoie à SysV, vous utiliseriez

ps -e |grep cron

ou

ps -el |grep cron 

pour une liste contenant plus que le pid et le nom du processus. Bien sûr, vous pouvez sélectionner les champs spécifiques à imprimer en utilisant l' -o <field,field,...>option.

Tatjana Heuser
la source
Comment cette réponse est-elle portable? (Vous dites que différentes formes de la commande ps devraient être utilisées sur différentes plates-formes)
peterh
ps est malheureusement l'un de ces outils avec un ensemble d'options différent pour le même résultat en fonction de leur ascendance. Donc, à moins que vous n'écriviez votre propre enveloppe (encore une fois incompatible avec quoi que ce soit d'autre) autour de cela, la voie à suivre serait de connaître les principales lignes du patrimoine et de s'adapter en conséquence. C'est différent lorsque vous créez un script - là, vous utiliserez ces différences pour déterminer sur quelle branche vous vous trouvez et adapter le comportement de votre script. Bottom line: vous aurez besoin de savoir les deux. Exemple célèbre: le script "configure" de Larry Wall. Citation célèbre: Félicitations, vous n'utilisez pas Eunice.
Tatjana Heuser
5

En rassemblant les différentes suggestions, la version la plus propre que j'ai pu proposer (sans grep peu fiable qui déclenche des parties de mots) est:

kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

kill -0 ne tue pas le processus mais vérifie s'il existe et renvoie ensuite true, si vous n'avez pas de pidof sur votre système, stockez le pid lorsque vous lancez le processus:

$ mysql &
$ echo $! > pid_stored

puis dans le script:

kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
Gletscher
la source
3

J'utilise pgrep -l httpdmais je ne suis pas sûr qu'il soit présent sur n'importe quelle plateforme ...
Qui peut confirmer sur OSX?

olibre
la source
Merci @Johnsyweb. Pouvez-vous également vérifier pidofs'il vous plaît? OK tu as fait. Je vous remercie. Nous devrions donc trouver quelque chose d'autre fonctionnant sous OSX ... Votre base est ps|greppeut-être la solution unique ;-)
olibre
1

Vous devez connaître le PID de votre processus.

Lorsque vous le lancez, son PID sera enregistré dans la $!variable. Enregistrez ce PID dans un fichier.

Ensuite, vous devrez vérifier si ce PID correspond à un processus en cours. Voici un script squelette complet:

FILE="/tmp/myapp.pid"

if [ -f $FILE ];
then
   PID=$(cat $FILE)
else
   PID=1
fi

ps -o pid= -p $PID
if [ $? -eq 0 ]; then
  echo "Process already running."  
else
  echo "Starting process."
  run_my_app &
  echo $! > $FILE
fi

Basé sur la réponse de peterh. L'astuce pour savoir si un PID donné est en cours d'exécution est dans l' ps -o pid= -p $PIDinstruction.

icarito
la source
0

Cette approche peut être utilisée dans le cas où les commandes «ps», «pidof» et rest ne sont pas disponibles. J'utilise personnellement procfs très fréquemment dans mes outils / scripts / programmes.

   egrep -m1  "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3

Petite explication de ce qui se passe:

  1. -m1 - arrêter le processus lors de la première correspondance
  2. "mysqld $ | httpd $" - grep correspondra aux lignes qui se sont terminées sur mysqld OU httpd
  3. / proc / [0-9] * - bash correspondra à la ligne commençant par n'importe quel nombre
  4. cut - il suffit de diviser la sortie par le délimiteur '/' et d'extraire le champ 3
Tom Lime
la source
0

Ceci imprime le nombre de processus dont le nom de base est "chrome-browser":

ps -e -o args= | awk 'BEGIN{c=0}{
 if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
 if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"

Si cela imprime "0", le processus n'est pas en cours d'exécution. La commande suppose que le chemin du processus ne contient pas d'espace de rupture. Je n'ai pas testé cela avec des processus suspendus ou des processus zombie.

Testé en utilisant gwakcomme awkalternative sous Linux.

Voici une solution plus polyvalente avec quelques exemples d'utilisation:

#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
 local quiet=1;
 shift
else
 local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
 name=$2
 if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
 if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}

process='chromium-browser'

printf "Process \"${process}\" is "
if isProcessRunning -q "$process" 
 then printf "running.\n"
 else printf "not running.\n"; fi

printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"
jarno
la source
0

Voici ma version. Fonctionnalités:

  • vérifie le nom exact du programme (premier argument de la fonction). la recherche de "mysql" ne correspondra pas à l'exécution de "mysqld"
  • recherche les arguments du programme (deuxième argument de la fonction)

scénario:

#!/bin/bash

# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
    for i in $(pidof $1); do
        cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
        if [ $? -eq 0 ]; then
            return 0
        fi
    done
    return 1
}

isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
    echo "not running, starting..."
fi
Raigedas
la source
0

Aucune des réponses n'a fonctionné pour moi, alors voici la mienne:

process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
  echo "Process is not running."
else
  echo "Process is running."
fi

Explication:

|tr -d '\n'

Cela supprime le retour chariot créé par le terminal. Le reste peut être expliqué par ce post.

Jeff Luyet
la source
-1

La fonction shell suivante, basée uniquement sur les commandes et options standard POSIX, devrait fonctionner sur la plupart des systèmes Unix et Linux (sinon aucun). :

isPidRunning() {
  cmd=`
    PATH=\`getconf PATH\` export PATH
    ps -e -o pid= -o comm= |
      awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
  `
  [ -n "$cmd" ] &&
    printf "%s is running\n%s\n\n" "$1" "$cmd" ||
    printf "%s is not running\n\n" $1
  [ -n "$cmd" ]
}

$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd

$ isPidRunning ksh
ksh is running
5230 ksh

$ isPidRunning bash
bash is not running

Notez qu'il s'étouffera lorsqu'il passera le nom de commande douteux "0]" et échouera également à identifier les processus ayant un espace intégré dans leurs noms.

Notez également que la solution la plus votée et acceptée nécessite des psoptions non portables et utilise gratuitement un shell qui, malgré sa popularité, n'est pas garanti d'être présent sur toutes les machines Unix / Linux ( bash)

jlliagre
la source
$ isPidRunning 0]affiche par exemple "0] est en cours d'exécution 3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [migration / 0] 35 [watchdog / 0]" ici.
jarno
Pourquoi avez-vous besoin de ce truc PATH?
jarno
J'ai développé la solution plus loin ici .
jarno
@jarno Le paramètre PATH est une condition requise pour que le script soit portable. Sinon, il échouerait au moins sur Solaris 10 et versions antérieures et éventuellement sur d'autres implémentations Unix.
jlliagre
1
@jarno Je pourrais le faire mais je devrai aussi répéter ce paramètre PATH pour awk. Notez que je suis revenu à l'ancienne syntaxe de backtick pour être portable avec la syntaxe pré-POSIX bourne shells.
jlliagre