Essayer d'écrire un script shell qui continue de tester un serveur à distance, mais il continue de tomber dans l'instruction else lorsque je me déconnecte


9

Essayer ici d'écrire un script shell qui continue de tester mon serveur et de m'envoyer un e-mail lorsqu'il tombe en panne.

Le problème est que lorsque je me déconnecte de la connexion ssh, malgré son exécution &à la fin de la commande, comme ./stest01.sh &, il tombe automatiquement dans autre chose et continue de me poster sans interruption, jusqu'à ce que je me reconnecte et le tue.

#!/bin/bash
while true; do
    date > sdown.txt ;
    cp /dev/null pingop.txt ;
    ping -i 1 -c 1 -W 1 myserver.net > pingop.txt &
    sleep 1 ;
    if
        grep "64 bytes" pingop.txt ;
    then
        :
    else
        mutt -s "Server Down!" myemail@address.com < sdown.txt ;
        sleep 10 ;
    fi
done

1
Je ne suis pas un expert bash, mais que fait le colon :? Ça aurait du sens pour moi s'il s'agissait d'un point-virgule ;...
Ned64

3
@ Ned64 The :ne fait rien. C'est ce pour quoi il est conçu. Ici, au lieu d'inverser le test, ils l'utilisent pour faire un no-op auparavant else.
Kusalananda

@Kusalananda OK, merci. Je pensais que ce pourrait être une faute de frappe qui pourrait expliquer le problème.
Ned64

1
Je suis également confus pourquoi on essaierait de laisser un script shell en cours d'exécution après la déconnexion. Les temporisateurs cron ou systemd ne seraient-ils pas un meilleur choix pour cela?
Cliff Armstrong

Réponses:


20

Lorsque GNU grepessaie d'écrire son résultat, il échouera avec un état de sortie différent de zéro, car il n'a nulle part où écrire la sortie, car la connexion SSH a disparu.

Cela signifie que l' ifinstruction prend toujours la elsebranche.

Pour illustrer cela (ce n'est pas exactement ce qui se passe dans votre cas, mais cela montre ce qui se passe si GNU grepn'est pas en mesure d'écrire sa sortie):

$ echo 'hello' | grep hello >&- 2>&-
$ echo $?
2

Ici, nous greppour la chaîne qui echoproduit, mais nous fermons les deux flux de sortie pour grepqu'il ne puisse écrire nulle part. Comme vous pouvez le voir, l'état de sortie de GNU grepest 2 plutôt que 0.

Ceci est particulier à GNU grep, grepsur les systèmes BSD ne se comportera pas de la même manière:

$ echo 'hello' | grep hello >&- 2>&-    # using BSD grep here
$ echo $?
0

Pour y remédier, assurez-vous que le script ne génère pas de sortie. Vous pouvez le faire avec exec >/dev/null 2>&1. De plus, nous devrions utiliser grepavec son -qoption car nous ne sommes pas du tout intéressés à voir la sortie de celui-ci (cela accélérerait également généralement le grepcar il n'a pas besoin d'analyser tout le fichier, mais dans ce cas, cela fait très peu différence de vitesse car le fichier est si petit).

En bref:

#!/bin/sh

# redirect all output not redirected elsewhere to /dev/null by default:
exec >/dev/null 2>&1

while true; do
    date >sdown.txt

    ping -c 1 -W 1 myserver.net >pingop.txt

    if ! grep -q "64 bytes" pingop.txt; then
        mutt -s "Server Down!" myemail@address.com <sdown.txt
        break
    fi

    sleep 10
done

Vous pouvez également utiliser un test pingdirectement, supprimant le besoin d'un des fichiers intermédiaires (et supprimant également l'autre fichier intermédiaire qui ne contient vraiment qu'un horodatage):

#!/bin/sh

exec >/dev/null 2>&1

while true; do
    if ! ping -q -c 1 -W 1 myserver.net; then
        date | mutt -s "Server Down!" myemail@address.com
        break
    fi

    sleep 10
done

Dans les deux variantes du script ci-dessus, j'ai choisi de quitter la boucle en cas d'échec pour atteindre l'hôte, juste pour minimiser le nombre d'e-mails envoyés. Vous pouvez à la place remplacer le breakpar exemple sleep 10mou quelque chose si vous vous attendez à ce que le serveur réapparaisse finalement.

J'ai également légèrement modifié les options utilisées avec pingcar cela -i 1n'a pas beaucoup de sens -c 1.

Plus court (sauf si vous souhaitez qu'il continue à envoyer des e-mails lorsque l'hôte est inaccessible):

#!/bin/sh

exec >/dev/null 2>&1

while ping -q -c 1 -W 1 myserver.net; do
    sleep 10
done

date | mutt -s "Server Down!" myemail@address.com

En tant que tâche cron exécutée toutes les minutes (continuerait d'envoyer des e-mails toutes les minutes si le serveur continuait à être en panne):

* * * * * ping -q -c 1 -W 1 >/dev/null 2>&1 || ( date | mail -s "Server down" myemail@address.com )

L'utilisation >&-fermera le fd (comme dans, le descripteur de fichier 1 est fermé), tandis que la fermeture de la connexion SSH aura un effet différent (un descripteur de fichier sera toujours là, mais pas connecté à quoi que ce soit de l'autre côté.) Je pense que le point se tient toujours, ce qui est que GNU grep quitte non nul s'il essaie d'écrire la sortie et cela échoue. Oui, la meilleure solution consiste simplement à vérifier directement l'état de sortie du ping.
filbranden

4
Il pourrait être plus sûr de tout rediriger vers / depuis / dev / null pour le script entier en ajoutant exec </dev/null >/dev/null 2>&1près du début. De cette façon, si par exemple pingdécide d'écrire quelque chose sur stderr, cela ne posera pas de problème.
Gordon Davisson

@GordonDavisson Je ne vois pas vraiment de raison de retirer stdin d' /dev/nullici, mais j'ai trié la sortie. Merci pour la suggestion.
Kusalananda
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.