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.