Sprawdzanie, czy wyjście polecenia zawiera określony ciąg w skrypcie powłoki

117

Piszę skrypt powłoki i próbuję sprawdzić, czy dane wyjściowe polecenia zawierają określony ciąg. Myślę, że prawdopodobnie muszę użyć grep, ale nie jestem pewien jak. Czy ktoś wie?

user1118764
źródło
Czy polecenie musi działać dalej po wygenerowaniu ciągu wyjściowego, którego szukasz, czy może zostać natychmiast zamknięte w tym czasie? (Twoje dwie odpowiedzi różnią się pod tym względem semantyką).
Charles Duffy,

Odpowiedzi:

97

Przetestuj zwracaną wartość grep:

./somecommand | grep 'string' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
fi

co jest wykonywane idiomatycznie, jak to:

if ./somecommand | grep -q 'string'; then
   echo "matched"
fi

i również:

./somecommand | grep -q 'string' && echo 'matched'
perreal
źródło
2
Ten kod nie działa ze wszystkimi powłokami POSIX: standard POSIX wymaga tylko =bycia operatorem porównania, a nie ==; patrz pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
Charles Duffy,
4
Ponadto grep 'string' &>/dev/nulljest niezgodny z POSIX i znacznie wolniejszy do wykonania (jeśli stringpojawia się wcześnie w długim strumieniu wyjściowym) niż grep -q string. [Zastrzeżenie polega na tym, że jeśli chcesz mieć pewność, somecommandże działa nawet po wyemitowaniu string, w takim przypadku użycie grep -q- poprzez zamknięcie standardowego wejścia i wyjście po pierwszym wystąpieniu string- może przynieść efekt przeciwny do zamierzonego]. (Re: "niezgodne z POSIX", &>to rozszerzenie - patrz pubs.opengroup.org/onlinepubs/009695399/utilities/ ... opisujące obsługę przekierowań narzuconych przez POSIX).
Charles Duffy,
Pomogłoby, gdyby zostało wyjaśnione, dlaczego to działa / co robi każdy parametr, aby zachęcić do pełnego zrozumienia składni
redfox05
158

Testowanie $?jest anty-wzorcem

if ./somecommand | grep -q 'string'; then
  echo "matched"
fi
mata
źródło
Jeśli przypadkiem chcesz tylko przetestować stały ciąg, dodać F i x opcje: grep -Fxq F oznacza stałe (nie interpretować) i X na całej linii
Erdal G.
4
Dlaczego testowanie $?jest anty-wzorcem?
Witalij Zdanevich
1
@VitalyZdanevich Zakładam, ponieważ nie jest odporny na współbieżność.
Konrad Reiche
@VitalyZdanevich, na przykład, testowanie $?nie ustawia poprzednich poleceń jako „sprawdzonych” dla celów set -elub ERRpułapki, więc twój program może zakończyć się w przypadkach, gdy chcesz, aby po prostu powrócił później celowo fałszywą ścieżką. Po drugie, $?to niestabilny stan globalny - łatwo przez przypadek wyrzucić jego wartość. Na przykład, jeśli dodasz wiersz logowania, taki jak echo "Exit status is $?", nowa wartość w stanie $?się statusem wyjścia echo.
Charles Duffy
6

Inną opcją jest sprawdzenie zgodności wyrażeń regularnych w wyniku polecenia.

Na przykład:

[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"
Noam Manos
źródło
1

Czysty warunkowy skrypt powłoki if / else:

if ./somecommand | grep -q 'some_string'; then
  echo "exists"
else
  echo "doesn't exist"
fi
Ehsan Barkhordar
źródło