Pourquoi ai-je un statut de sortie différent pour ps | grep dans un script?

11

Je lance le script ci-dessous:

#!/bin/bash

ps ax  | grep -q [v]arnish
if [ $? -eq 0 ];then
        echo varnish is running...
        exit 0
else
        echo "Critical : varnish is not running "
        exit 2
fi

La sortie est comme ::

[root@server ~]# sh -x check_varnish_pro.sh
+ ps ax
+ grep -q '[v]arnish'
+ '[' 0 -eq 0 ']'
+ echo varnish is running...
varnish is running...
+ exit 0

Lorsque je lance la même chose en ligne de commande, j'obtiens le statut de sortie 1:

[root@server ~]# ps ax  | grep -q [v]arnish; echo $?
1

Le cas est comme le vernis n'est pas installé sur le serveur. Ce script fonctionne très bien sur un serveur où le vernis est installé.

Pourquoi un statut de sortie différent lorsqu'il est exécuté à l'aide d'un script et d'une ligne de commande? Comment améliorer ce script?

prado
la source
Utilisez un véritable système de supervision des processus, pas ce type de piratage. Votre système d'exploitation aura presque certainement un moyen intégré de garantir que vos démons que vous souhaitez conserver sont automatiquement redémarrés en cas d'échec, que ce soit par le démarrage, daemontools, systemd, launchd ou l'une des nombreuses, nombreuses autres alternatives. Tous seront plus robustes et capables que ce type de piratage à la main.
Charles Duffy

Réponses:

10

Lorsque vous exécutez un script nommé check_varnish_pro.shtest

ps ax  | grep -q [v]arnish

réussit car un script nommé check_vernis est en_pro cours d'exécution.

AlexP
la source
14

En général, c'est une mauvaise idée d'essayer l'approche simple avec pset grepd'essayer de déterminer si un processus donné est en cours d'exécution.

Vous feriez bien mieux d'utiliser pgreppour cela:

if pgrep "varnish" >/dev/null; then
  echo "Varnish in running"
else
  echo "Varnish is not running"
fi

Voir le manuel pour pgrep. Sur certains systèmes (probablement pas sous Linux), vous obtenez un -qindicateur qui correspond au même indicateur pour greplequel vous vous débarrassez de la nécessité de rediriger /dev/null. Il existe également un -findicateur qui effectue la correspondance sur la ligne de commande complète plutôt que sur le nom du processus uniquement. On peut également limiter la correspondance aux processus appartenant à un utilisateur spécifique utilisant -u.

L'installation pgrepvous donne également accès à pkillce qui vous permet de signaler des processus en fonction de leurs noms.

De plus, s'il s'agit d'un démon de service et si votre système Unix a un moyen de l'interroger pour obtenir des informations (par exemple, s'il est opérationnel et non), alors c'est la bonne façon de le vérifier.

Sous Linux, vous avez systemctl( systemctl is-active --quiet varnishretournera 0 s'il est en cours d'exécution, 3 sinon), sur OpenBSD vous avez rcctl, etc.


Passons maintenant à votre script:

Dans votre script, vous analysez la sortie de ps ax. Cette sortie contiendra le nom du script lui-même check_varnish_pro.sh, qui contient évidemment la chaîne varnish. Cela vous donne un faux positif. Vous l'auriez repéré si vous l'aviez exécuté sans -qindicateur greppendant le test.

#!/bin/bash
ps ax | grep '[v]arnish'

L'exécuter:

$ ./check_varnish_pro.sh
31004 p1  SN+     0:00.04 /bin/bash ./check_varnish_pro.sh

Un autre problème est que, même si vous essayez de «masquer» le grepprocessus d'être détecté par greplui-même en utilisant [v]le modèle. Cette approche échouera si vous exécutez le script ou la ligne de commande dans un répertoire contenant un fichier ou un répertoire nommé varnish(auquel cas vous obtiendrez à nouveau un faux positif). Cela est dû au fait que le modèle n'est pas entre guillemets et que le shell effectuera la globalisation des noms de fichiers avec lui.

Voir:

bash-4.4$ set -x
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep '[v]arnish'
bash-4.4$ touch varnish
+ touch varnish
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep varnish
91829 p2  SN+p    0:00.02 grep varnish

La présence du fichier varnishentraînera le remplacement du shell [v]arnishpar le nom de fichier varnishet vous obtenez un hit sur le modèle dans la table de processus (le grepprocessus).

Kusalananda
la source
4
car tout est un fichier "sous Linux".
zee
@ z_- Je ne sais pas trop comment il est connecté, mais cela reste vrai même sur les unités non Linux.
Kusalananda
4
Pas seulement le processus grep; le nom du script check_varnish_pro.shest également un facteur.
TNW
@TNW Je n'ai pas remarqué cela au début, mais vous avez raison. J'ajouterai cela.
Kusalananda
3

@AlexP explique très succinctement ce qui se passe réellement, mais l'idée de @ Kusalananda d' utiliser pgrep/ pkillpour un processus critique est fortement déconseillée . De meilleures solutions comprennent:

  • Demander au service s'il fonctionne. systemctl status varnishddevrait prendre soin de cela sur une installation moderne * nix.
  • Si, dans une circonstance malheureuse, vous n'avez pas de service disponible, vous pouvez simplement modifier le script de démarrage pour signaler le problème dès la fin du processus:

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
    
  • Vous pouvez également modifier le script qui démarre le service pour enregistrer le PID, puis vérifier régulièrement l'état avec kill -0 "$pid".
l0b0
la source
Je suis d'accord, je parlais simplement des aspects de script shell du problème. Notez que cela systemctln'est presque disponible que sur Linux (AFAIK), et pas sur tous les systèmes modernes de type Unix.
Kusalananda
La question d'origine avait la balise "linux"; Je ne sais pas pourquoi cela a été supprimé par @muru.
l0b0
Merci l0b0. J'avais deux questions "Pourquoi" et "Comment s'améliorer". @ La réponse d'AlexP a résolu ma première question et votre réponse est une meilleure solution pour la deuxième question. Mais Kusalananda explique des choses liées à cela qui, je pense, seront utiles pour les personnes qui ont des problèmes similaires. Donc, je ne sais pas trop lequel accepter comme réponse.
prado