Operator „i” dla instrukcji „if” w Bash

168

Próbuję utworzyć prosty skrypt Bash, aby sprawdzić, czy witryna nie działa iz jakiegoś powodu operator „and” nie działa:

#!/usr/bin/env bash

WEBSITE=domain.com
SUBJECT="$WEBSITE DOWN!"
EMAILID="[email protected]"
STATUS=$(curl -sI $WEBSITE | awk '/HTTP\/1.1/ { print $2 }')
STRING=$(curl -s $WEBSITE | grep -o "string_to_search")
VALUE="string_to_search"

if [ $STATUS -ne 200 ] && [[ "$STRING" != "$VALUE" ]]; then
    echo "Website: $WEBSITE is down, status code: '$STATUS' - $(date)" | mail -s "$SUBJECT" $EMAILID
fi

Operator „-a” również nie działa:

if [ $STATUS -ne 200 ] -a [[ "$STRING" != "$VALUE" ]]

Czy mógłbyś również doradzić, kiedy użyć:

  • pojedyncze i podwójne nawiasy kwadratowe
  • nawias

?

HTF
źródło
3
Czy mógłbyś bardziej precyzyjnie określić, co „nie działa”? Czy masz konkretny komunikat o błędzie, czy po prostu nie zapewnia on oczekiwanych wyników?
Julien Vivenot
W rzeczywistości otrzymywałem „jednoargumentowy operator oczekiwany”, więc wygląda na to, że cytowanie pomaga
HTF,
-ama dwulicowość. W połączeniu z testpoleceniem stylu powłoki Bourne'a [, oznacza to and. Gdy jest używane jako wyrażenie warunkowe , sprawdza, czy plik istnieje. Tak, jest to mylące, najlepiej tego unikać.
cdarke

Odpowiedzi:

254

To, co masz, powinno działać, chyba że ${STATUS}jest puste. Prawdopodobnie lepiej byłoby zrobić:

if ! [ "${STATUS}" -eq 200 ] 2> /dev/null && [ "${STRING}" != "${VALUE}" ]; then

lub

if [ "${STATUS}" != 200 ] && [ "${STRING}" != "${VALUE}" ]; then

Trudno powiedzieć, ponieważ nie pokazałeś nam dokładnie, co jest nie tak z twoim skryptem.

Osobista opinia: nigdy nie używaj [[. Pomija ważne komunikaty o błędach i nie można go przenosić do różnych powłok.

William Pursell
źródło
2
Jeśli STATUSjest pusty, kod z @HTF nie powiódłby się -ne: unary operator expected. W twoim przypadku to się nie uda integer expression expected, prawda?
Julien Vivenot
1
Rozumiem, że. Ale podkreślasz problem, który $STATUSmoże być pusty i sugerujesz rozwiązanie (cytując). Twoje rozwiązanie nadal zawodzi z pustym STATUS, to wszystko, co miałem na myśli.
Julien Vivenot
1
@jvivenot Masz rację. (Moja odpowiedź na twój komentarz została udzielona zanim zredagowałeś swój komentarz, kiedy twój komentarz po prostu przeczytał "kod ... nie powiódłby się". Prostym rozwiązaniem jest użycie ${STATUS:-0". Będzie edytować.
William Pursell
Przepraszamy, Twoja edycja nadal nie działa. Na przykład: STATUS=; [ $STATUS -ne 13 ] 2>/dev/null && echo foonie wyprowadza foo, mimo że powinien (pusty różni się od 13). To, co zasugerowałeś jako pierwszy, ${STATUS:-0}wygląda o wiele lepiej.
Julien Vivenot
@jvivenot Używanie ${STATUS:-0}nie powiedzie się, jeśli STATUS=foo, ale ! [ "$STATUS" -eq 200 ] 2> /dev/null && echo foodziała. IMO, lepiej jednak unikać -eqi używać !=.
William Pursell
28

Spróbuj tego:

if [ $STATUS -ne 200 -a "$STRING" != "$VALUE" ]; then
BrenanK
źródło
pracował dla mnie. Myślę, że może być więcej niż jeden sposób, ale na razie jestem z tego zadowolony.
Kushal Ashok
26

Spróbuj tego:

if [ ${STATUS} -ne 100 -a "${STRING}" = "${VALUE}" ]

lub

if [ ${STATUS} -ne 100 ] && [ "${STRING}" = "${VALUE}" ]
AnshBikram
źródło
plus za najczystszy przykład
Paweł Cioch
12

Zacytować:

Operator „-a” również nie działa:

if [$ STATUS -ne 200] -a [["$ STRING"! = "$ VALUE"]]

Aby uzyskać bardziej szczegółowe wyjaśnienie: [i ]nie są to zastrzeżone słowa Bash. Słowo ifkluczowe wprowadza warunek, który ma być oceniany przez zadanie (warunek jest prawdziwy, jeśli wartość zwracana przez zadanie wynosi 0lub fałsz w innym przypadku).

W przypadku trywialnych testów istnieje testprogram ( man test).

Ponieważ niektórzy uważają, że takie linie if test -f filename; then foo bar; fiitp. Są irytujące, w większości systemów można znaleźć wywoływany program, [który w rzeczywistości jest tylko dowiązaniem symbolicznym do testprogramu. Gdy testjest wywoływana jako [, musisz dodać ]jako ostatni argument pozycyjny.

Więc if test -f filenamejest w zasadzie to samo (pod względem powstających procesów) jak if [ -f filename ]. W obu przypadkach testprogram zostanie uruchomiony i oba procesy powinny zachowywać się identycznie.

Oto twój błąd: if [ $STATUS -ne 200 ] -a [[ "$STRING" != "$VALUE" ]]przeanalizuje if+ do jakiejś pracy, przy czym praca będzie wszystkim oprócz ifsiebie. Zadanie jest tylko prostym poleceniem (Bash mówi o czymś, co powoduje pojedynczy proces), co oznacza, że ​​pierwsze słowo ( [) to polecenie, a reszta to argumenty pozycyjne. Po pierwszym są pozostałe argumenty] .

Również nie, [[jest rzeczywiście słowem kluczowym Bash, ale w tym przypadku jest przetwarzane tylko jako zwykły argument polecenia, ponieważ nie znajduje się na początku polecenia.

Jo So
źródło