Dlaczego otrzymuję inny status wyjścia dla ps | grep w skrypcie?

11

Uruchomiam poniżej skryptu:

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

Dane wyjściowe są jak:

[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

Kiedy uruchamiam to samo w wierszu poleceń, otrzymuję status wyjścia jako 1:

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

Sprawa jest taka, jakby lakier nie został zainstalowany na serwerze. Ten skrypt działa dobrze na serwerze, na którym zainstalowany jest lakier.

Po co różny status wyjścia, gdy jest uruchamiany za pomocą skryptu i wiersza poleceń? Jak ulepszyć ten skrypt?

prado
źródło
Używaj prawdziwego systemu nadzoru procesu, a nie tego rodzaju hakerów. Twój system operacyjny prawie na pewno będzie miał wbudowany sposób, aby zapewnić, że demony, które chcesz pozostać, zostaną automatycznie zrestartowane po awarii, czy to na starcie, daemontools, systemd, launchd, czy też jedna z wielu, wielu innych alternatyw. Wszystkie będą bardziej wytrzymałe i zdolne niż tego rodzaju ręcznie zwijane hakery.
Charles Duffy

Odpowiedzi:

10

Po uruchomieniu skryptu o nazwie check_varnish_pro.shtest

ps ax  | grep -q [v]arnish

odnosi sukces, ponieważ działa skrypt o nazwie check_lakier_pro .

AlexP
źródło
14

Ogólnie rzecz biorąc, złym pomysłem jest wypróbowanie prostego podejścia psi greppróba ustalenia, czy dany proces działa.

Lepiej byłoby użyć pgrepdo tego:

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

Zobacz instrukcję dla pgrep. W niektórych systemach (prawdopodobnie nie w Linuksie) otrzymujesz -qflagę odpowiadającą tej samej fladze, dla grepktórej pozbywasz się potrzeby przekierowywania /dev/null. Istnieje również -fflaga, która wykonuje dopasowanie w pełnym wierszu poleceń, a nie tylko w nazwie procesu. Można również ograniczyć dopasowanie do procesów należących do konkretnego użytkownika -u.

Instalowanie pgrepdaje również dostęp do tego, pkillco pozwala sygnalizować procesy na podstawie ich nazw.

Ponadto, jeśli jest to demon usługi i jeśli twój system uniksowy ma sposób na zapytanie go o informacje (np. Czy jest uruchomiony, czy nie), to jest to właściwy sposób sprawdzania go.

W systemie Linux masz systemctl( systemctl is-active --quiet varnishzwróci 0, jeśli jest uruchomiony, 3 w przeciwnym razie), w OpenBSD masz rcctlitp.


Teraz do skryptu:

W skrypcie analizujesz dane wyjściowe z ps ax. Dane wyjściowe będą zawierać nazwę samego skryptu check_varnish_pro.sh, który oczywiście zawiera ciąg varnish. To daje fałszywie pozytywny wynik. Zauważyłbyś to, gdybyś testował go bez -qflagi grep.

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

Uruchamianie:

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

Innym problemem jest to, że chociaż próbujesz „ukryć” sam grepproces przed wykryciem grepza pomocą [v]wzorca. Takie podejście zakończy się niepowodzeniem, jeśli zdarzy się, że uruchomisz skrypt lub wiersz poleceń w katalogu, w którym znajduje się nazwa pliku lub katalogu varnish(w takim przypadku ponownie otrzymasz fałszywy wynik dodatni). Wynika to z faktu, że wzorzec nie jest cytowany, a powłoka będzie wykonywać z nim globbing nazw plików.

Widzieć:

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

Obecność pliku varnishspowoduje, że powłoka zastąpi [v]arnishnazwę pliku varnishi otrzymasz trafienie we wzorzec w tabeli procesów ( grepproces).

Kusalananda
źródło
4
ponieważ wszystko jest plikiem „w Linuksie”.
Zee
@ z_- Nie jestem pewien, w jaki sposób jest podłączony, ale dotyczy to nawet uniksowych systemów Linux.
Kusalananda
4
Nie tylko proces grep; nazwa skryptu check_varnish_pro.shjest również czynnikiem.
TNW
@TNW Na początku tego nie zauważyłem, ale masz rację. Dodam to.
Kusalananda
3

@AlexP wyjaśnia bardzo krótko, co się rzeczywiście dzieje, ale @ idei Kusalananda dnia używając pgrep/ pkillkrytycznego procesu jest zdecydowanie odradzane . Lepsze rozwiązania obejmują:

  • Prosząc usługę czy to działa. systemctl status varnishdpowinien się tym zająć w nowoczesnej instalacji * nix.
  • Jeśli z jakiegoś niefortunnego powodu nie masz dostępnej usługi, możesz po prostu zmienić skrypt startowy, aby zgłosić problem, gdy tylko proces się zakończy:

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
  • Alternatywnie zmień skrypt, który uruchamia usługę, aby rejestrował PID, a następnie okresowo sprawdzaj stan za pomocą kill -0 "$pid".
l0b0
źródło
Zgadzam się, właśnie omawiałem aspekty problemu związane ze skryptami powłoki. Zauważ, że systemctljest prawie dostępna tylko w systemie Linux (AFAIK), a nie we wszystkich nowoczesnych systemach uniksowych.
Kusalananda
Pierwotne pytanie miało znacznik „linux”; Nie jestem pewien, dlaczego zostało to usunięte przez @muru.
l0b0
Dzięki, l0b0. Miałem dwa pytania: „Dlaczego” i „Jak poprawić”. @ Odpowiedź AlexP rozwiązała moje pierwsze pytanie, a twoja odpowiedź jest lepszym rozwiązaniem dla drugiego pytania. Ale Kusalananda wyjaśnia rzeczy związane z tym, które moim zdaniem będą pomocne dla osób mających podobne problemy. Więc jestem teraz zmieszany, co przyjąć jako odpowiedź.
prado