Jak sprawdzić, czy polecenie się powiodło?


234

Czy jest jakiś sposób, aby sprawdzić, czy wystąpił błąd podczas wykonywania polecenia?

Przykład:

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

Próbowałem już to zrobić, ale wygląda na to, że to nie działa. Nie wiem jak to zrobić.


9
Preferuj $ (foo) nad backticks `foo` , ponieważ możesz go zagnieździć i łatwiej odróżnić go od apostrofów.
— użytkownik nieznany

1
BTW, musisz zdefiniować funkcję ( valid) przed jej wywołaniem.
— wjandrea

Odpowiedzi:


344

Zwracana wartość jest przechowywana w $?. 0 oznacza sukces, inne oznaczają błąd.

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

Jak każda inna wartość tekstowa, możesz przechowywać ją w zmiennej do przyszłego porównania:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

Dla możliwych operatorów porównania, patrz man test.


Fajnie ... czy mogę zatrzymać błąd wyjściowy? !! , ponieważ w tym przypadku mam błąd 2: błąd polecenia „tekst” ex, nie znaleziono pliku i mój błąd „tekst” Który w tym przypadku nie powiódł się na przykład
— moata_u

@moata_u: możesz zapisać wartość w zmiennej, jak pokazano w mojej odpowiedzi.
— Lekensteyn,

@moata_u: Musisz wstawić ;przed elsei fi: `if ...; następnie ...; inaczej ...; fi
— Lekensteyn,


1
@Blauhirn [ $? ](lub równoważnie test $?) nie działa, ponieważ zwraca $?liczbę (0, 1 itd.), Która nie jest równa null. Zapoznaj się z dokumentacjątest : „Jeśli WYRAŻENIE zostanie pominięte,„ test ”zwróci fałsz. Jeśli WYRAŻENIE jest pojedynczym argumentem,„ test ”zwróci fałsz, jeśli argument jest pusty, a prawda w przeciwnym razie.”
— Lekensteyn,

87

Jeśli potrzebujesz tylko wiedzieć, czy polecenie zakończyło się powodzeniem, czy nie, nie zawracaj sobie głowy testowaniem $?, po prostu przetestuj polecenie bezpośrednio. Na przykład:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

A przypisanie wyniku do zmiennej nie zmienia wartości zwracanej (cóż, chyba że zachowuje się inaczej, gdy standardowe wyjście nie jest oczywiście terminalem).

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals wyjaśnia ifbardziej szczegółowo.


Co zrobić, jeśli chcesz zrobić coś innego niż rozgałęzianie, np. Przechowywanie wartości logicznej tego, czy nie powiodło się w pliku .ini? Wtedy twoja zmienna wyjściowa tego nie robi, ale $?robi to, więc nie masz racji twierdząc, że bezpośrednie testowanie polecenia jest zdecydowanie lepsze.
— Timothy Swan

Przypisanie wyjścia do zmiennej może zmienić wartość zwracaną, gdy ktoś użyje localpolecenia, tj. local foo=$(false); echo $?;Tworzy 0na wyjściu. Ale dotyczy localto tylko funkcji bash.
— Cromax

26
command && echo OK || echo Failed

Jeśli commandzwraca błąd na ekranie, jak go ukryć?
— Sigur

Jeśli commandwypisuje błędy do stderr, możesz użyć formularza command 2> /dev/null && echo OK || echo Failed. Do 2> /dev/nullprzekierowania stderr wyjście do /dev/null. Jednak niektóre narzędzia wypiszą błędy na standardowe wyjście (mimo że jest to zła praktyka). W takim przypadku możesz pominąć 2 z przekierowania, ale stracisz dane wyjściowe z polecenia. Ta metoda sprawdzania sukcesu jest dobra w przypadku prostej logiki trójskładnikowej, ale w przypadku bardziej złożonych zachowań najlepiej jest sprawdzić $?skuteczność polecenia lub użyć ifmetody blokowej opisanej w odpowiedzi @ geirha.
— Bender the Greatest

17

$? powinien zawierać status wyjścia z poprzedniego polecenia, który powinien wynosić zero, bez błędu.

Coś w stylu;

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

w większości przypadków łatwiej jest używać konstruktora && do łączenia poleceń, które muszą być od siebie zależne. Tak cd /nonexistant && echo success!by nie powtórzyć sukces, ponieważ przerwy dowodzenia przed &&. Następstwem tego jest ||, gdzie cd /nonexistant || echo fail będzie echo nie dlatego cd powiodło się. (staje się to przydatne, jeśli użyjesz czegoś takiego jak || exit, co zakończy skrypt, jeśli poprzednie polecenie się nie powiedzie.)


Fajnie ... czy mogę zatrzymać błąd wyjściowy? !! , ponieważ w tym przypadku mam błąd 2: błąd polecenia „tekst” ex, nie znaleziono pliku i mój błąd „tekst” Który w tym przypadku nie powiódł się na przykład
— moata_u


5
command && echo $? || echo $?

Masz na myśli command; echo $??
— Javier Buzzi

Nie, moja linia jest poprawna, podaje rzeczywisty kod wyniku jako liczbę, niezależnie od tego, czy sukces, czy porażka.
— modrobert

1
Ok, proszę wyjaśnij mi różnice: true && echo $? || echo $?/ true; echo $?i false && echo $? || echo $?/ false; echo $?- przekonasz się, że robią dokładnie to samo: D
— Javier Buzzi

Tak, ten sam wynik, ale bez warunku. Pierwotnie zadane pytanie brzmiało: „Jak sprawdzić, czy polecenie się powiodło?”, Opierało się na poprzednich odpowiedziach. command && echo "success: $?" || echo "fail: $?"
— Wydaje

5

Należy zauważyć, że if...then...fii &&/ lub ||typ podejścia dotyczy statusu wyjścia zwracanego przez polecenie, które chcemy przetestować (0 w przypadku powodzenia); jednak niektóre polecenia nie zwracają niezerowego statusu wyjścia, jeśli polecenie zakończyło się niepowodzeniem lub nie mogło poradzić sobie z danymi wejściowymi. Oznacza to, że zwykłe ifi &&/ ||podejścia nie będą działać dla tych konkretnych poleceń.

Na przykład w systemie Linux GNU filenadal wychodzi z 0, jeśli otrzymał nieistniejący plik jako argument i findnie mógł zlokalizować określonego pliku 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 potencjalnym sposobem na poradzenie sobie z sytuacją jest odczyt stderr/ stdinkomunikaty, np. Te, które zwróciły filepolecenie lub parsują dane wyjściowe polecenia jak w find. W tym celu casemożna użyć instrukcji.

$ 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

(To jest odpowiedź mojej własnej odpowiedzi na powiązane pytanie na unix.stackexchange.com )


1

Jak wspomniano w wielu innych odpowiedziach, wystarczy prosty test $?tego typu

if [ $? -eq 0 ]; then something; fi

Jeśli chcesz sprawdzić, czy polecenie się nie powiodło , możesz użyć krótszej wersji w bash(ale być może przesadzonej) w następujący sposób:

if (($?)); then something; fi

Działa to przy użyciu (( ))trybu arytmetycznego, więc jeśli polecenie zwróciło success, tj. $? = 0Wtedy test oceni, do ((0))którego testu false, w przeciwnym razie wróci true.

Aby przetestować sukces , możesz użyć:

if ! (($?)); then something; fi

ale jest już niewiele krótszy niż pierwszy przykład.


1
konstruktywna krytyka?
— afuna,


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.