Jak warunkowo coś zrobić, jeśli polecenie zakończyło się powodzeniem lub niepowodzeniem

Jak mogę zrobić coś takiego w bashu?

if "`command` returns any error"; then echo "Returned an error" else echo "Proceed..." fi 

Odpowiedź

Jak warunkowo coś zrobić, jeśli polecenie zakończyło się powodzeniem lub niepowodzeniem

To jest dokładnie to, co bash Instrukcja „s if powoduje:

if command ; then echo "Command succeeded" else echo "Command failed" fi 

Dodawanie informacji z komentarzy: nie” t w tym przypadku należy użyć składni []. [ samo w sobie jest poleceniem, bardzo zbliżonym do test. Jest to prawdopodobnie najczęściej używane polecenie w if, które może prowadzić do założenia, że jest to część składni powłoki. Ale jeśli chcesz sprawdzić, czy polecenie się powiodło, czy nie, użyj samego polecenia bezpośrednio z if, jak pokazano powyżej.

Komentarze

  • Zauważ, że średnik jest ważny.
  • Możesz też po prostu umieścić then w osobnym wierszu.
  • @Joe: Myślę, że masz na myśli if ! command ; then ... ; fi. [ jest samo w sobie poleceniem i ' nie jest w tym przypadku potrzebne.
  • @Joe: Moja droga ma również tę zaletę, że jest poprawny. if [ ! command ] nie ' nie wykonuje command; traktuje command jako ciąg i traktuje go jako prawdę, ponieważ ma niezerową długość. [ jest synonimem polecenia test
  • Ups. ' zgadzasz się.

Odpowiedź

Małe rzeczy co ma się wydarzyć, jeśli polecenie powłoki działa, możesz użyć konstrukcji &&:

rm -rf somedir && trace_output "Removed the directory" 

Podobnie małe rzeczy, które mają się wydarzyć, gdy polecenie powłoki się nie powiedzie, możesz użyć ||:

rm -rf somedir || exit_on_error "Failed to remove the directory" 

Lub obu

rm -rf somedir && trace_output "Removed the directory" || exit_on_error "Failed to remove the directory" 

Prawdopodobnie nierozsądne jest robić wiele z tymi konstrukcjami, ale czasami mogą one znacznie zwiększyć przejrzystość sterowania.

Komentarze

  • Są krótsze i (przynajmniej w niektórych muszlach) szybsze. Wzdrygam się przypominając sobie potworny skrypt instalacyjny Ultrix napisany tylko z tych warunkowych konstrukcji, które kiedyś próbowałem rozszyfrować …

Odpowiedź

Sprawdź wartość $?, który zawiera wynik wykonania ostatniego polecenia / funkcji:

#!/bin/bash echo "this will work" RESULT=$? if [ $RESULT -eq 0 ]; then echo success else echo failed fi if [ $RESULT == 0 ]; then echo success 2 else echo failed 2 fi 

Komentarze

  • Chociaż technicznie poprawne (a więc nie gwarantuje negatywnego głosu), nie używa idiomu Bash ' s if. Wolę odpowiedź Keitha Thompsona '.
  • Ten idiom ma zalety – zachowuje zwracaną wartość. W sumie uważam, że ten jest potężniejszy, choć bardziej szczegółowy. ' jest również bardziej czytelny.
  • Co to jest ” Bash ' s if idiom „?
  • @Nowaker Fakt, że jedynym celem if jest zrobienie to. Wszystkie warunki kontroli przepływu w Bashu sprawdzają $? za kulisami; że ' jest tym, co robią. Wyraźne badanie jego wartości powinno być niepotrzebne w większości przypadków i jest to zazwyczaj początkujący antywzor.
  • Wolę to ze względu na czytelność. Główne polecenie jest zazwyczaj bardzo długie. Umieszczenie go w instrukcji „, jeśli ” powoduje słabą czytelność.

Odpowiedź

U mnie zadziałało:

command && echo "OK" || echo "NOK" 

if command powiedzie się, a następnie echo "OK" jest wykonywane, a ponieważ się powiodło, wykonywanie zostaje zatrzymane. W przeciwnym razie && jest pomijane, a echo "NOK" jest wykonywany.

Komentarze

  • Jeśli chcesz coś zrobić, jeśli to się nie powiedzie, zachowaj kod zakończenia (do wyświetlenia w wierszu polecenia lub do przetestowania w skrypcie), możesz to zrobić: command && echo "OK" || c=$?; echo "NOK"; $(exit $c)
  • @ Sam-Hasler: shouldn ' t, który jest command && echo "OK" || (c=$?; echo "NOK"; (exit $c))?
  • Ponadto, jeśli echo "OK" część może sama niepowodzenie, to jest lepiej: command && (echo "OK"; exit 0) || (c=$?; echo "NOK"; (exit $c))
  • @ jrw32982, Dobrze, ' użyłem poprzedniej konstrukcji, ale nie to drugie.
  • Prawdziwa odpowiedź znajduje się w komentarzach, dzięki wszystkim!

Odpowiedź

Należy zauważyć, że if...then...fi i && / || rodzaj podejścia dotyczy statusu wyjścia zwróconego przez polecenie, które chcemy przetestować (0 w przypadku sukcesu); jednak niektóre polecenia nie zwracają niezerowego kodu wyjścia, jeśli polecenie zawiodło lub nie radzi sobie z danymi wejściowymi. Oznacza to, że zwykłe metody if i && / || nie zadziałają w przypadku tych konkretnych poleceń.

Na przykład w systemie Linux GNU file nadal kończy się z 0, jeśli jako argument otrzymał nieistniejący plik i find nie można znaleźć pliku określonego przez użytkownika.

$ find . -name "not_existing_file" $ echo $? 0 $ file ./not_existing_file ./not_existing_file: cannot open `./not_existing_file" (No such file or directory) $ echo $? 0 

W takich przypadkach jednym z potencjalnych sposobów rozwiązania problemu jest przeczytanie stderr / stdin wiadomości, np. te, które zwróciły polecenie file, lub przeanalizują dane wyjściowe polecenia, jak w przypadku find. W tym celu można użyć instrukcji case.

$ file ./doesntexist | while IFS= read -r output; do > case "$output" in > *"No such file or directory"*) printf "%s\n" "This will show up if failed";; > *) printf "%s\n" "This will show up if succeeded" ;; > esac > done This will show up if failed $ find . -name "doesn"texist" | if ! read IFS= out; then echo "File not found"; fi File not found 

Odpowiedź

Najbardziej podatna na błędy, jaką mogłem wymyślić, to:

  • Najpierw pobierz wartość. Załóżmy, że robisz coś takiego:

RR=$?

Nie tylko w tej sytuacji, ale także w innych, z którymi możesz się spotkać, rozważ:

zdefiniowana zmienna:

$ AA=1 ; if (( "10#0${AA}" == 1 )) ; then echo yes ; else echo no ; fi

Odpowiedź: tak

$ AA=1 ; if (( "10#0${AA}" != 1 )) ; then echo yes ; else echo no ; fi

Odpowiedź: nie

niezdefiniowana zmienna:

$ AA=1 ; if (( "10#0${BB}" == 1 )) ; then echo yes ; else echo no ; fi

Odpowiedź: nie

$ AA=1 ; if (( "10#0${BB}" != 1 )) ; then echo yes ; else echo no ; fi

Odpowiedź: tak

$ AA=1 ; if (( "10#0${BB}" == 0 )) ; then echo yes ; else echo no ; fi

Odpowiedź: tak

Zapobiega to wszelkiego rodzaju błędom.

Prawdopodobnie znasz całą składnię, ale tutaj niektóre wskazówki:

  • Używaj cudzysłowów. Unikaj "blank" bycia nothing.
  • Nowa nowoczesna notacja dla zmiennych to ${variable}.
  • Dodanie zera połączonego przed liczbą również pozwala uniknąć „żadnego numeru”.
  • Ale poczekaj, dodanie zera powoduje, że liczba staje się base-8. Pojawi się błąd taki jak:
    • value too great for base (error token is "08") dla liczb powyżej 7. To wtedy pojawia się 10#:
    • 10# wymusza base-10.

Odpowiedź

Możesz to zrobić:

if ($( ping 4.4.4.4 -c1 > /dev/null )) ; then echo "ping response succsess!!!" fi 

Komentarze

  • To działa, ale jest skomplikowane. Gdy ' wykonujesz polecenie ping w podpowłoce podpowłoki, dane wyjściowe ping są przechwytywane w celu uruchomienia go jako polecenia. Ale ponieważ dane wyjściowe są przekierowywane do / dev / null, zawsze będzie to pusty ciąg. Więc ' nie uruchamiasz niczego w podpowłoce, co oznacza, że poprzedni stan wyjścia (podpowłoki zastępującej polecenia, czyli ping) zostanie zachowany. Oczywiście prawidłowy sposób jest if ping ...; then tutaj.

Odpowiedź

Jak zauważono w innym miejscu tego wątku, pierwotne pytanie w zasadzie odpowiada samo sobie. Oto ilustracja pokazująca, że warunki if również mogą być zagnieżdżone.

W tym przykładzie if sprawdza, czy plik istnieje i czy jest zwykłym plikiem. Jeśli te warunki są spełnione, sprawdź, czy ma rozmiar większy niż 0.

#!/bin/bash echo "Which error log are you checking today? " read answer if [ -f /opt/logs/$answer*.errors ] then if [ -s /opt/logs/$answer*.errors ] then echo "Content is present in the $answer error log file." else echo "No errors are present in the $answer error log file." fi else echo "$answer does not have an error log at this time." fi 

Komentarze

  • Tak właśnie działa Twoja odpowiedź, ale Twoja odpowiedź nie odpowiada na pytanie.
  • @JeffSchaller, dziękuję za uwagę. Zmieniłem post, aby zawierał odniesienie do pytania.

Odpowiedź

#!/bin/bash if command-1 ; then echo "command-1 succeeded and now running from this block command-2" command-2 else echo "command-1 failed and now running from this block command-3" command-3 fi 

Komentarze

Odpowiedź

Można to zrobić w ten sposób, ponieważ $? podaje stan ostatniego wykonanego polecenia.

Więc mogłoby być

#!/bin/sh ... some command ... if [ $? == 0 ] ; then echo "<the output message you want to display>" else echo "<failure message>" fi 

Komentarze

  • Głos przeciw: to po prostu parafraza wcześniejszą odpowiedź, która została słusznie skrytykowana za bycie jednostronnym.
  • Właściwie to właśnie tego szukałem, ponieważ ' próbuję aby polecenie ” ” zakończyło się niepowodzeniem skryptu jako część ” set -e ” co nie ' t, jeśli ' jest częścią if.Nie powinno to ' być odrzuconym.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *