La manière «appropriée» de tester si un service est en cours d'exécution dans un script

98

Mon problème:

J'écris un script bash dans lequel j'aimerais vérifier si un service donné est en cours d'exécution.

Je sais comment faire cela manuellement, avec $ service [service_name] status.

Mais (surtout depuis le passage à systemd), qui imprime un tas de texte un peu compliqué à analyser. J'ai supposé qu'il existe une commande pour les scripts avec une sortie simple ou une valeur de retour que je peux vérifier.

Mais googler autour ne donne qu'une tonne de résultats "Oh, juste ps aux | grep -v grep | grep [service_name]". Cela ne peut pas être la meilleure pratique, est-ce? Que se passe-t-il si une autre instance de cette commande est en cours d'exécution, mais pas une autre démarrée par le script init SysV?

Ou devrais-je simplement me taire et me salir les mains avec un petit pgrep?

Nick S
la source

Réponses:

141

systemctla une is-activesous-commande pour cela:

systemctl is-active --quiet service

sortira avec le statut zéro si serviceest actif, différent de zéro sinon, ce qui le rend idéal pour les scripts:

systemctl is-active --quiet service && echo Service is running

Si vous omettez, --quietcela affichera également l'état actuel sur sa sortie standard.

Comme l'a souligné don_crissti , certaines unités peuvent être actives même si rien ne fonctionne pour fournir le service: les unités marquées comme «RemainAfterExit» sont considérées comme actives si elles sortent avec succès, l'idée étant qu'elles fournissent un service ne nécessitant pas de démon. ( par exemple, ils configurent certains aspects du système). Les unités impliquant des démons ne seront toutefois actives que si le démon est toujours en cours d'exécution.

Stephen Kitt
la source
Attention aux services personnels. Ils sont seulement inactiveou activatinget les deux systemctl statuset systemctl is-activesortent avec 3. (à partir de systemd-241 ) Solution de contournement:systemctl show service | grep -qx ActiveStatus=activating
Alois Mahdal
@Alois, je me demande quel genre de scénario vous avez rencontré où vous voudriez qu'un service onehot soit actif; Avez-vous un exemple?
Stephen Kitt
Bien sûr, @StephenKitt. L'outil foofait quelque chose au système impliquant un redémarrage et utilise un service ponctuel, par exemple, foo_cleanuplors du prochain démarrage pour nettoyer les choses. Je teste cela (mon script est également planifié en tant que service) et je souhaite collecter les erreurs par la suite, mais quand est-il ensuite (musique vsauce)? L’un des critères est qu’il foo_cleanupest terminé ("a cessé d’être actif").
Alois Mahdal
Il est peut-être intéressant de souligner que l'option "échec" est également une option et qu'elle est utile si vous devez effectuer une action en fonction d'un service non démarré.
Phill Healey
33

systemctla un mode approprié pour le script; utilisez showplutôt que status, et ajoutez les options -p/ --propertieset --valuepour obtenir uniquement le résultat souhaité.

Voici un exemple (d'un système Ubuntu 17.04):

$ systemctl show -p SubState --value NetworkManager
running

Courir (ou autrement) est un SubState. Si vous voulez savoir si un service est actif, utilisez la propriétéActiveState

$ systemctl show -p ActiveState --value x11-common
inactive
$ systemctl show -p SubState --value x11-common
dead

Notes de la man:

show [PATTERN...|JOB...]
           Show properties of one or more units, jobs, or the manager
           itself. If no argument is specified, properties of the
           manager will be shown. If a unit name is specified, properties
           of the unit are shown, and if a job ID is specified,
           properties of the job are shown. By default, empty properties
           are suppressed. Use --all to show those too. To select specific
           properties to show, use --property=. This command is intended
           to be used whenever computer-parsable output is required. Use
           status if you are looking for formatted human-readable output.

-p, --property=
           When showing unit/job/manager properties with the show command,
           limit display to properties specified in the argument. The
           argument should be a comma-separated list of property names,
           such as "MainPID". Unless specified, all known properties are
           shown. If specified more than once, all properties with the
           specified names are shown. Shell completion is implemented for
           property names.

--value
           When printing properties with show, only print the value, and
           skip the property name and "=".
Zanna
la source
2
+1 pour une réponse sophistiquée. veuillez spécifier les distributions qui accepteront l’ --versionoption avec systemctl.
SK Venkat
11

En complément de la réponse de Zanna, l' --valueoption for systemctl showa été introduite avec la version 230 de systemd . Il est donc possible qu’il ne soit pas disponible sur certaines distributions comme Debian Jessie.

Dans ce cas, on peut émuler l'option en utilisant sed:

$ systemctl show -p ActiveState sshd | sed 's/ActiveState=//g'
active
$ systemctl show -p SubState sshd | sed 's/SubState=//g'  
running
Oxmel
la source
1
+1 pour avoir souligné la version & valeur de l'intro --value qui ne fonctionnerait pas.
SK Venkat
3

Je trouve cela utile pour l'exécution en ligne de commande ou si vous créez des scripts.

Copié de @StephenKitt

Ceci vérifiera si le service est en panne et effectuera un redémarrage du service.

systemctl is-active --quiet <service name> || <service name> restart

the ||there vérifie si la valeur renvoyée par systemctl est non nulle, ce qui signifie qu'elle n'est pas active comme l'explique l'auteur.

astérisque
la source
Vous pouvez également utiliser `is-failed´ pour tester si un redémarrage est nécessaire. Il semble un peu plus intuitif de redémarrer un service en échec.
Phill Healey
oui, mais pour moi .. je voulais pratiquer moi-même et supposer que tout fonctionne quand ce n'est pas le cas. afin que je puisse aller vérifier d'autres choses avec elle. si vous voulez simplement vérifier s’il ne fonctionne pas, alors «échec» est un choix légitime. :)
astérisque le
3


Je suis trop tard pour le parti, cependant utiliser systemctl est actif avec &&et ||dans ce script ne sera pas le cas tout le temps. Le texte ci-dessous est celui que j’ai utilisé pour tomcat, mais que je peux utiliser dans une méthode prenant des arguments et donnant le nom de service comme arguments si vous devez vérifier plusieurs services, mais dont le champ est hors de portée.

STATUS=`systemctl is-active tomcat.service`
  if [[ ${STATUS} == 'active' ]]; then
    echo "Execute your tasks ....."
  else 
    echo " Service not running.... so exiting "  
    exit 1  
  fi

C’est ainsi que j’ai utilisé .... Je partage juste le mien.

et pour la simplicité et la facilité, suivez les explications suivantes:

systemctl -q is-active tomcat.service  && echo "Tomcat Runnung" || echo "Service is not running at all "
SAGAR Nair
la source
Comment est-ce mieux que simplement if systemctl is-active --quiet tomcat.service? En outre, [[n'est pas shell standard.
Toby Speight le
@TobySpeight Vous devez lire mon message un peu plus, comme je l’ai mentionné dans mon message "C’est ainsi que je me suis servi de ... partageant simplement le mien." Je n’ai jamais dit, c’est une utilisation standard du shell, si vous en faites un support unique, il le deviendra alors, mais c’est hors de portée ici. De plus, je mentionne ci-dessous l'utilisation facile d'une seule ligne pour le faire en utilisant &&et ||.
SAGAR Nair le
2

Au lieu d'utiliser la commande sed comme dans la réponse d'Oxmel, il suffit de l'utiliser cut -d'=' -f 2pour tous les types de propriétés interrogées:

par exemple:

$ systemctl show -p ActiveState sshd | cut -d'=' -f2
active
$ systemctl show -p SubState sshd | cut -d'=' -f2
running
Mohamed El
la source
C'est bien, mais vous devez vraiment expliquer ce que font ces commandes.
Phill Healey
-1

Je viens de trouver ce bon petit script:

#!/bin/bash
service=replace_me_with_a_valid_service

if (( $(ps -ef | grep -v grep | grep $service | wc -l) > 0 ))
then
  echo "$service is running!!!"
else
  /etc/init.d/$service start
fi

La source

Terry
la source
Tous les services ne disposent pas d'un exécutable du même nom et tout utilisateur peut exécuter une commande qui correspond accidentellement - il s'agit d'une recette pour un sinistre.
Toby Speight le