Warum erhalte ich für ps | einen anderen Exit-Status? grep in einem Skript?

11

Ich laufe unter Skript:

#!/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

Die Ausgabe ist wie ::

[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

Wenn ich dasselbe in der Befehlszeile ausführe, erhalte ich den Beendigungsstatus 1:

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

Der Fall ist, als wäre kein Lack auf dem Server installiert. Dieses Skript funktioniert gut auf einem Server, auf dem Lack installiert ist.

Warum unterschiedlicher Exit-Status bei Ausführung über Skript und Befehlszeile? Wie kann ich dieses Skript verbessern?

Prado
quelle
Verwenden Sie ein echtes Prozessüberwachungssystem, nicht diese Art von Hackery. Ihr Betriebssystem verfügt mit ziemlicher Sicherheit über eine integrierte Methode, um sicherzustellen, dass Ihre Daemons, die Sie auf dem Laufenden halten möchten, bei einem Fehler automatisch neu gestartet werden, sei es Upstart, Daemontools, Systemd, Launchd oder eine der vielen, vielen anderen Alternativen. Alle von ihnen werden robuster und leistungsfähiger sein als diese Art von handgerolltem Hackery.
Charles Duffy

Antworten:

10

Wenn Sie ein Skript mit dem Namen check_varnish_pro.shtest ausführen

ps ax  | grep -q [v]arnish

ist erfolgreich, weil ein Skript namens check_Lack_pro ausgeführt wird.

AlexP
quelle
14

Im Allgemeinen ist es eine schlechte Idee , den einfachen Ansatz mit , um zu versuchen psund grepzu versuchen , einen bestimmten Prozess zu bestimmen , ob ausgeführt wird .

Sie wären dafür viel besser dran pgrep:

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

Siehe das Handbuch für pgrep. Auf einigen Systemen (wahrscheinlich nicht unter Linux) erhalten Sie ein -qFlag, das demselben Flag entspricht, für grepdas keine Umleitung mehr erforderlich ist /dev/null. Es gibt auch ein -fFlag, das die Übereinstimmung in der vollständigen Befehlszeile und nicht nur im Prozessnamen ausführt. Man kann die Übereinstimmung auch auf Prozesse beschränken, die zu einem bestimmten Benutzer gehören -u.

Durch die Installation erhalten pgrepSie auch Zugriff, mit pkilldem Sie Prozesse anhand ihrer Namen signalisieren können.

Auch wenn dies ein Service - Daemon , und wenn Ihr Unix - System eine Möglichkeit , Abfragen für Informationen (zB ob es sich um und läuft oder nicht) hat, dann ist das die richtige Art und Weise auf sie zu prüfen.

Unter Linux haben Sie systemctl( systemctl is-active --quiet varnishwird 0 zurückgeben, wenn es ausgeführt wird, andernfalls 3), unter OpenBSD rcctlusw.


Nun zu Ihrem Skript:

In Ihrem Skript analysieren Sie die Ausgabe von ps ax. Diese Ausgabe enthält den Namen des Skripts selbst check_varnish_pro.sh, das offensichtlich die Zeichenfolge enthält varnish. Dies gibt Ihnen ein falsches Positiv. Sie hätten dies entdeckt, wenn Sie es beim Testen ohne -qFlag ausgeführt hätten grep.

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

Ausführen:

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

Ein weiteres Problem ist, dass Sie zwar versuchen, den grepProzess grepdurch die Verwendung [v]im Muster vor dem Erkennen durch sich selbst zu "verbergen" . Dieser Ansatz schlägt fehl, wenn Sie das Skript oder die Befehlszeile in einem Verzeichnis ausführen, in dem eine Datei oder ein Verzeichnis benannt varnishist (in diesem Fall erhalten Sie erneut ein falsches Positiv). Dies liegt daran, dass das Muster nicht in Anführungszeichen gesetzt ist und die Shell damit das Dateinamen-Globbing ausführt.

Sehen:

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

Das Vorhandensein der Datei varnishführt dazu, dass die Shell durch [v]arnishden Dateinamen ersetzt wird varnishund Sie einen Treffer auf das Muster in der Prozesstabelle (dem grepProzess) erhalten.

Kusalananda
quelle
4
weil alles eine datei "in linux land" ist.
Zee
@ z_- Ich bin mir nicht ganz sicher, wie es verbunden ist, aber dies gilt auch für Nicht-Linux-Unices.
Kusalananda
4
Nicht nur der Grep-Prozess; Das benannte Skript check_varnish_pro.shist ebenfalls ein Faktor.
TNW
@TNW Das habe ich zuerst nicht bemerkt, aber du hast recht. Ich werde das hinzufügen.
Kusalananda
3

@AlexP erklärt sehr prägnant, was tatsächlich passiert, aber @ Kusalanandas Idee , pgrep/ pkillfür einen kritischen Prozess zu verwenden, wird dringend abgeraten . Bessere Lösungen umfassen:

  • Fragen Sie den Dienst, ob er ausgeführt wird. systemctl status varnishdsollte sich bei einer modernen * nix-Installation darum kümmern.
  • Wenn Sie unter unglücklichen Umständen keinen Dienst zur Verfügung haben, können Sie einfach das Startskript ändern, um das Problem zu melden, sobald der Prozess beendet wird:

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
  • Alternativ können Sie das Skript ändern, mit dem der Dienst gestartet wird, um die PID aufzuzeichnen, und dann den Status regelmäßig mit überprüfen kill -0 "$pid".
l0b0
quelle
Ich stimme zu, ich habe mich nur mit den Shell-Scripting-Aspekten des Problems befasst. Beachten Sie, dass dies systemctlfast nur unter Linux (AFAIK) und nicht auf allen modernen Unix-ähnlichen Systemen verfügbar ist.
Kusalananda
Die ursprüngliche Frage hatte das Tag "Linux"; Ich bin mir nicht sicher, warum das von @muru entfernt wurde.
10b0
Danke l0b0. Ich hatte zwei Fragen "Warum" und "Wie man sich verbessert". Die Antwort von @ AlexP hat meine erste Frage gelöst und Ihre Antwort ist eine bessere Lösung für die zweite Frage. Aber Kusalananda erklärt die damit verbundenen Dinge, von denen ich denke, dass sie für Menschen mit ähnlichen Problemen hilfreich sind. Also bin ich jetzt verwirrt, was ich als Antwort akzeptieren soll.
Prado