Comment déterminer si un processus est en cours d'exécution et comment l'utiliser pour créer un script shell conditionnel?

108

Comment puis-je déterminer si un processus est en cours d'exécution ou non, puis qu'un script bash exécute des tâches en fonction de cette condition?

Par exemple:

  • si le processus abcest en cours, faites ceci

  • Si cela ne fonctionne pas, faites-le.

Nirmik
la source
1
Il est important de noter qu'aucune des solutions ci-dessous ne tient compte de l'état du processus. Un commentaire sur l'une de mes questions m'a amené ici, mais une réponse m'a éclairé sur différents états d'un programme, comme zombieprocessus '(pas ce que je qualifierais de processus «en cours»). Une liste complète de ce que les STATvaleurs de colonne, dans le résultat de ps, indiquent, est ici pour ceux qui sont enclins à écrire une réponse qui tient compte de cela ou à éditer la leur
user66001
Discussion connexe: unix.stackexchange.com/questions/74185/…
blong
meilleure façon de vérifier le processus existe: stackoverflow.com/questions/3043978/…
Trevor Boyd Smith

Réponses:

166

Un script bash pour faire quelque chose comme ça pourrait ressembler à ça:

#!/bin/bash

# Check if gedit is running
# -x flag only match processes whose name (or command line if -f is
# specified) exactly match the pattern. 

if pgrep -x "gedit" > /dev/null
then
    echo "Running"
else
    echo "Stopped"
fi

Ce script vérifie simplement si le programme "gedit" est en cours d'exécution.

Ou vous pouvez seulement vérifier si le programme ne fonctionne pas comme ceci:

if ! pgrep -x "gedit" > /dev/null
then
    echo "Stopped"
fi
John Vrbanac
la source
@DreadPirateShawn pouvez-vous me dire pourquoi utiliser / dev / null et pas simplement un 0? L'utilisation du numéro rend le code plus lisible, du moins pour un noob (comme moi). Pas de redirection, pas de rien
Silviu
2
@ Silviu hein? Google /dev/null: "/ dev / null redirige la sortie standard de la commande vers le périphérique null, qui est un périphérique spécial qui rejette les informations qui y sont écrites" ... using 0redirige la sortie de la commande vers un fichier appelé 0. Dans ce cas, je vous conseillerais de vous familiariser davantage avec le logiciel > /dev/null. Vous le verrez partout car il s’agit du moyen standard / approprié de supprimer la sortie.
DreadPirateShawn
Merci Woot, je l'ai utilisé pour un joli petit script qui vérifie si un programme est en cours d'exécution avant de s'exécuter. (Bien que je devais l'étendre un peu car l'exécutable de google chrome ne porte pas le même nom que sa commande d'exécution, le nom de l'exécutif est simplement chrome.)
Cestarian le
3
S'il vous plaît ajouter le -xparamètre à pgrepafin qu'il recherche l'application exacte ou sinon, il obtiendra une erreur fausse s'il trouve la même chaîne dans le nom d'une autre application. Je viens de passer 1 heure pour le découvrir.
Thanos Apostolou
1
Pour vérifier si le programme ne fonctionne pas, utilisez! pgrep
Mohammed Noureldin le
36

Toute solution qui utilise quelque chose comme ps aux | grep abcou qui pgrep abcest défectueux.

Pourquoi?

Comme vous ne vérifiez pas si un processus spécifique est en cours d'exécution, vous vérifiez si des processus en cours d'exécution correspondent abc. Tout utilisateur peut facilement créer et exécuter un exécutable nommé abc(ou contenant abcquelque part dans son nom ou ses arguments), ce qui provoque un faux positif pour votre test. Il existe différentes options que vous pouvez appliquer à ps, grepet pgreppour affiner la recherche, mais vous toujours pas un test fiable.

Alors, comment puis-je tester de manière fiable pour un certain processus en cours d'exécution?

Cela dépend de ce que vous avez besoin du test.

Je veux m'assurer que le service abc est en cours d'exécution et sinon, le démarrer

C'est à cela que servent init et upstart. Ils vont démarrer le service et s'assurer que son pid est stocké dans un pidfile. Essayez de redémarrer le service (via init ou upstart) et il vérifiera le pidfile, et le démarrera s'il n'est pas là ou annulera s'il est déjà en cours d'exécution. Ce n'est toujours pas fiable à 100%, mais c'est aussi proche que possible.

Voir Comment puis-je vérifier si mon serveur de jeu est toujours en cours d'exécution ... pour d'autres solutions.

ABC est mon script. Je dois m'assurer qu'une seule instance de mon script est en cours d'exécution.

Dans ce cas, utilisez un lockfile ou un lockdir. Par exemple

#!/usr/bin/env bash

if ! mkdir /tmp/abc.lock; then
    printf "Failed to acquire lock.\n" >&2
    exit 1
fi
trap 'rm -rf /tmp/abc.lock' EXIT  # remove the lockdir on exit

# rest of script ...

Voir la FAQ Bash 45 pour d'autres moyens de verrouillage.

geirha
la source
3
Bien que cela soit techniquement vrai, je n'ai jamais personnellement rencontré un tel problème dans la vie réelle. La plupart des programmes ne changent pas de nom de manière à rompre les scripts. Ainsi, pour les scripts simples, quelque chose comme pgrepou psest parfaitement adéquat et votre approche semble exagérée. Si vous écrivez un script destiné au public, vous devez l’écrire de la manière la plus sûre possible.
Scott Severance
2
@ScottSeverance Les programmes ne changent pas de nom. cela nécessiterait une intervention peu importe. Ce sont d’autres utilisateurs exécutant le même programme, ou d’autres programmes portant des noms similaires, qui provoqueront soudainement des faux positifs dans le script et lui imposeront une action fausse. Je préfère juste "fonctionne" plutôt que "fonctionne principalement".
geirha
2
Je me suis mal exprimé. Mais beaucoup d’entre nous exploitons des systèmes mono-utilisateurs. Et dans une situation à plusieurs utilisateurs, il est facile de grep aussi pour le nom d'utilisateur.
Scott Severance
1
Que se passe-t-il si votre script échoue pendant l'exécution et meurt avant de déverrouiller le fichier?
jp093121
2
@ jp093121 L'interruption EXIT est déclenchée à la fermeture du script. Qu'elle se ferme parce qu'elle atteint la fin du script, une commande de sortie ou reçoit un signal (qui peut être traité), la rmcommande est exécutée. Donc, tant qu'il se termine après que le piège a été mis, le verrou devrait être parti.
geirha
18

C'est ce que j'utilise:

#!/bin/bash

#check if abc is running
if pgrep abc >/dev/null 2>&1
  then
     # abc is running
  else
     # abc is not running
fi

En clair: si 'pgrep' renvoie 0, le processus est en cours d'exécution, sinon ce n'est pas le cas.


Lecture connexe:

Bash Scripting :: Comparaisons de chaînes

Manuels Ubuntu pgrep

Zuul
la source
merci! j’ai essayé ça aussi n ça marche à merveille aussi
Nirmik
pgrepa la même "caractéristique" de limite de 15 caractères mentionnée précédemment, ainsi, par exemple pgrep gnome-power-manager, elle échouerait également
Thorsen le
1
Assurez-vous d'utiliser l' -xoption de pgrep : "Ne faites correspondre que les processus dont le nom (ou la ligne de commande si -f est spécifié) correspond exactement au modèle."
Alastair Irvine
5

J'ai l'habitude d'avoir un pidof -x $(basename $0)sur mes scripts pour vérifier s'il est déjà en cours d'exécution.

Rommel Cid
la source
2

Riffing sur l'idée de @ rommel-cid, vous pouvez utiliser pidofavec le || (||) pour exécuter une commande si le processus n'existe pas et && pour exécuter quelque chose si le processus existe, créant ainsi un conditionnel rapide if / then / else. Par exemple, voici un exemple avec un processus en cours d'exécution (mon navigateur chrome, dont le nom est "chrome") et un test pour un processus inexistant. J'ai supprimé la sortie standard en utilisant 1> / dev / null pour qu'elle ne soit pas imprimée:

$ (pidof chrome 1>/dev/null && echo "its running? ok, so am i then" ) || echo "it's not running? ok i'll run instea\
d"
its running? ok, so am i then
$ (pidof nosuchprocess 1>/dev/null && echo "its running? ok, so am i then" ) || echo "it's not running? ok i'll run\
 instead"
it's not running? ok i'll run instead
$
Yuvilio
la source
1

Aucune des solutions "simples" n'a fonctionné pour moi car le binaire que je dois vérifier n'est pas installé à l'échelle du système. Je dois donc vérifier avec le chemin, ce qui nécessite à son tour une ps -ef | grepapproche:

app="$_sdir/Logic 1.2.18 (64-bit)/Logic"

app_pid=`ps -ef | grep "$app" | awk '{print $2}'`

if `ps -p $app_pid > /dev/null`; then
    echo "An instance of logic analyzer is appear to be running."
    echo "Not starting another instance."
    exit 5
else
    nohup "$app" &> /dev/null &
fi
ceremcem
la source
0

La première chose qui me vienne à l’esprit pour votre problème:
ps aux | grep -i abcmontrera les détails du processus s’il fonctionne. Vous pouvez faire correspondre le nombre de lignes ou le temps pour lequel il est exécuté et le comparer à zéro ou à toute autre manipulation. Lorsque vous exécutez la commande ci-dessus, il vous montrera au moins une ligne de sortie, c'est-à-dire des détails sur le processus créé par cette commande grep. Prenez donc soin de cela.
Cela devrait faire comme un simple bidouillage. Mettez-le dans le script bash et voyez si c'est utile.

drake01
la source
0

Utilisant start-stop-daemon:

/sbin/start-stop-daemon --background --make-pidfile --pidfile /tmp/foo.pid -S --startas /usr/bin/program -- arg1 arg2

Cela fonctionne comme utilisateur normal.

Martin Monperrus
la source
0

J'ai trouvé que la réponse acceptée postée par @John Vrbanac ne fonctionnait pas pour moi et que la réponse postée par @geirha ne répondait pas à la question initiale.

La solution de John Vrbanac n'a pas fonctionné pour vérifier si un processus PHP fonctionnait ou non pour moi, j'utilise CentOS 7.

La réponse de @ geirha s'assure seulement qu'une instance n'est pas déjà en cours d'exécution avant d'en démarrer une autre. Ce n'était pas la question initiale, la question initiale était de vérifier si un processus est en cours d'exécution ou non.

Voici ce qui a fonctionné pour moi:

Supposons que mon processus comporte la chaîne "Jane" dans son nom de processus. Cela va trouver si c'est en cours d'exécution ou non. Cela fonctionne pour les scripts BASH et PHP.

ps -aux | grep "[J]ane" > /dev/null 2>&1
if [[ "$?" == "0" ]]; then
    echo "It's running"
else
    echo "It's not running"
fi
Wayne Workman
la source
1
Eh bien, comme il s'agit d'un site de questions et réponses sur Ubuntu, il n'est pas surprenant que certaines des réponses fournies ici ne fonctionnent pas sur CentOS 7, car Linux est hors sujet ici. Les autres versions de Linux sont supportées sur unix.stackexchange.com
Elder Geek
Bien que l'auteur de la réponse utilise CentOS, cette réponse est toujours valable pour Ubuntu.
Phillip -Zyan K Lee- Stockmann
0
## bash

## function to check if a process is alive and running:

_isRunning() {
    ps -o comm= -C "$1" 2>/dev/null | grep -x "$1" >/dev/null 2>&1
}

## example 1: checking if "gedit" is running

if _isRunning gedit; then
    echo "gedit is running"
else
    echo "gedit is not running"
fi

## example 2: start lxpanel if it is not there

if ! _isRunning lxpanel; then
    lxpanel &
fi

## or

_isRunning lxpanel || (lxpanel &)

Remarque : pgrep -x lxpanelou pidof lxpanelindique toujours que le lxpanellogiciel est en cours d'exécution, même s'il est obsolète (zombie); afin d'obtenir un processus en vie, nous devons utiliser psetgrep

Bach Lien
la source
-1

Depuis le 23 septembre 2016, pgrep semble avoir besoin de l'option "-x" pour que le script de muru fonctionne.

#!/bin/bash

if pgrep -x "conky" > /dev/null 2>&1
then
  echo "conky running already"
else
  echo "now starting conky"
  conky
fi
exit 0

J'ai essayé et testé le script ci-dessus sur une machine Ubuntu 16.04.1. Prendre plaisir!

dzmanto
la source
-1
#!/bin/bash
while [ true ]; do     # Endless loop.
  pid=`pgrep -x ${1}`  # Get a pid.
  if [ -z $pid ]; then # If there is none,
    ${1} &             # Start Param to background.
  else
    sleep 60           # Else wait.
  fi
done
utilisateur7449824
la source
1
Bienvenue sur Ask Ubuntu! Je vous recommande de modifier cette réponse pour la développer avec des détails spécifiques sur ce que cela fait. (Voir aussi Comment puis-je écrire une bonne réponse? Pour des conseils généraux sur les types de réponses considérés comme les plus utiles sur AskUbuntu.)
David Foerster Le
-3

isProcessRunning () {if [$ (pidof $ 1)> / dev / null]; then retval = 'true'; sinon retval = 'false'; Fi; echo $ retval; }

isProcessRunning geany

vrai

Dominic
la source