Dlaczego 0 jest prawdą, a fałszem 1 w powłoce?

122
false; echo $?

Powyższe zostanie wyświetlone 1, co jest sprzeczne ze wszystkimi innymi językami programowania, które znam.

Jakiś powód w tym?

httpinterpret
źródło
3
Jest to również zgodne ze sposobem uniksowym ... nie zwracaj niczego po sukcesie.
Abdullah Jibaly
21
Ponieważ status wyjścia nie jest wartością logiczną. Proste.
Jens,
2
Należy pamiętać, że falsenie jest to wartość logiczna, jak w innych językach programowania. Jest to po prostu program znajdujący się pod adresem /bin/false( /usr/bin/falsena komputerze Mac), który ma zawsze zwracać kod zakończenia błędu 1. Podobnie w przypadku true. Więc nie ma tu czegoś takiego jak casting. Chodzi tylko o kody wyjścia.
Michaił Vasin
Powłoka jest interfejsem (użytkownika) systemu operacyjnego. Programy uniksowe itp. Stosują konwencję wychodzenia z 0 jako OK, z powodu podanego w odpowiedziach (możliwość komunikowania się z więcej niż jedną przyczyną niepowodzenia). Powłoka po prostu zachowuje tę konwencję, co sprawia, że ​​konstrukcje są if myprog; then echo OK; fiłatwe i intuicyjne. W przeciwnym razie, aby program zakończył się sukcesem, musiałbyś odwrócić każdy test!
Peter - Przywróć Monikę

Odpowiedzi:

93

To konwencja, ale szczególnie przydatna, kiedy się nad tym zastanowić. Ogólnie rzecz biorąc, jeśli program się powiedzie, to wszystko, co musisz wiedzieć. Jeśli jednak się nie powiedzie, być może będziesz musiał znać wszelkiego rodzaju informacje o awarii - dlaczego tak się stało, jak to naprawić itp. Zero oznacza „sukces” i niezerową awarię, co pozwala łatwo sprawdzić skuteczność. i zbadaj konkretny błąd, aby uzyskać więcej informacji, jeśli chcesz. Wiele interfejsów API i frameworków ma podobną konwencję - funkcje, które zakończą się sukcesem, zwracają 0, a te, które zawiodły, zwracają kod błędu opisujący konkretny przypadek niepowodzenia.

Carl Norum
źródło
6
Rozumiem tę odpowiedź, ale nadal nie rozumiem, dlaczego konwersja bool do int jest odwrócona. Czy istnieje „zwracana konwencja boolowska”, która mówi: jeśli zwrócisz prawdę, oznacza to, że nie ma błędów, jeśli zwrócisz fałsz, oznacza to, że wystąpił błąd (jak bardziej znana konwencja „liczba całkowita = kod błędu”)?
Guillaume86
1
Zakładając, że istnieje konwersja wartości boolowskiej na int oznacza, że ​​tak naprawdę nie zrozumiałeś odpowiedzi. Zero oznacza sukces, a wszystkie 1, 2, ..., 255 to kody błędów, które mogą pożytecznie komunikować różne scenariusze awarii. Szczególnym przykładem jest xargsużycie różnych kodów błędów z zakresu około 127, aby wskazać, w jaki sposób grupa poleceń zawiodła. Konwersja, którą można wykonać, to int do bool, gdzie 0 odwzorowuje sukces (który, jak sądzę, chcesz wyrazić jako prawda / 1; ale zdaj sobie sprawę, że jest to kolejna arbitralna konwencja) i wszystkie inne wartości na porażkę.
tripleee
79

Bash to język programowania (skryptów), ale jest też powłoką i interfejsem użytkownika. Jeśli 0był błąd, program mógł przedstawić tylko jeden rodzaj błędu.

Jednak w Bash każda wartość różna od zera jest błędem i możemy użyć dowolnej liczby z zakresu 1-255 do reprezentowania błędu. Oznacza to, że możemy mieć wiele różnych rodzajów błędów. 1jest błędem ogólnym, 126oznacza, że ​​plik nie może zostać wykonany, 127oznacza „polecenie nie zostało znalezione”, itd. Oto lista kodów wyjścia Bash o specjalnym znaczeniu, pokazująca niektóre z najczęściej występujących kodów zakończenia.

Istnieje również wiele rodzajów sukcesu (status wyjścia to 0). Jednak sukces pozwoli ci przejść do następnego kroku - możesz polubić wydrukowanie wyników na ekranie lub wykonać polecenie itp.

Stefana Lasiewskiego
źródło
8
Ta pragmatyczna odpowiedź, pokazująca użyteczność różnych kodów powrotu, jest lepsza od głoszenia niektórych innych odpowiedzi.
javadba
1
I dla samej przyjemności zaznaczę, że /usr/include/sysexits.hzwraca uwagę na wartości wyjściowe , które być może są bardziej aspiracyjne, mimo że reprezentowana przez nie konwencja sięga lat 80-tych. Ta konwencja istnieje poza zakresem bash.
ghoti,
2
Świetne, proste i pragmatyczne wyjaśnienie. To musi być na górze.
Rey Leonard Amorato
3
„Jeśli 0był błąd, to program mógł przedstawić tylko jeden rodzaj błędu” . To stwierdzenie jest kluczowe i powód, dla którego ta odpowiedź powinna być na górze.
rayryeng
1
@LuisLavaire To jest niezdefiniowane zachowanie. W praktyce liczba jest skracana; ale zdecydowanie nie byłoby „bardziej źle”, gdyby środowisko wykonawcze wygenerowało ostrzeżenie i / lub po prostu uległo awarii. System operacyjny zarezerwował dokładnie jeden bajt na te informacje i próbując wstawić więcej niż jeden bajt, z pewnością wystąpił błąd. Ale projektanci systemu operacyjnego prawdopodobnie wpadli w awarię pierwszego dnia, wzruszyli ramionami i zdecydowali, że najlepsze, co mogą zrobić, to po prostu zmniejszyć wartość i przejść dalej.
tripleee
30

Są tu dwa powiązane problemy.

Po pierwsze, pytanie OP: Dlaczego 0 jest prawdą, a fałsz to 1 w powłoce? a po drugie, dlaczego aplikacje zwracają 0 dla sukcesu i niezerowe dla niepowodzenia?

Aby odpowiedzieć na pytanie PO, musimy zrozumieć drugie pytanie. W licznych odpowiedziach na ten post opisano, że jest to konwencja, i wymieniono niektóre niuanse, które zapewnia ta konwencja. Poniżej podsumowano niektóre z tych subtelności.

Dlaczego aplikacje zwracają 0 w przypadku sukcesu i niezerowe w przypadku niepowodzenia?

Kod, który wywołuje operację, musi wiedzieć dwie rzeczy o statusie zakończenia operacji. Czy operacja zakończyła się pomyślnie? [* 1] A jeśli operacja nie zakończyła się pomyślnie, dlaczego operacja zakończyła się niepowodzeniem? Do określenia sukcesu można użyć dowolnej wartości. Ale 0 jest wygodniejszy niż jakakolwiek inna liczba, ponieważ można go przenosić między platformami. Podsumowując odpowiedź xibo na to pytanie z dnia 16 sierpnia 2011 r .:

Zero jest niezależne od kodowania.

Gdybyśmy chcieli zapisać jeden (1) w 32-bitowym słowie całkowitym, pierwsze pytanie brzmiałoby: „Big-endian word or little-endian word?”, A następnie „jak długie są bajty tworzące słowo little-endian? ”, podczas gdy zero zawsze będzie wyglądać tak samo.

Należy się również spodziewać, że niektórzy ludzie rzucają w pewnym momencie errno do zwęglenia lub zwarcia, a nawet do unoszenia się. (int) ((char) ENOLCK) nie jest ENOLCK, gdy znak nie jest co najmniej 8-bitowy (7-bitowe maszyny ASCII char są obsługiwane przez UNIX), podczas gdy (int) ((char) 0) jest 0 niezależne od detale architektoniczne char.

Po ustaleniu, że wartość 0 będzie zwracaną wartością sukcesu, sensowne jest użycie dowolnej wartości niezerowej dla niepowodzenia. Dzięki temu wiele kodów zakończenia pozwala odpowiedzieć na pytanie, dlaczego operacja się nie powiodła.

Dlaczego 0 jest prawdą, a fałszem 1 w powłoce?

Jednym z podstawowych zastosowań powłok jest automatyzacja procesów poprzez ich skrypty. Zwykle oznacza to wywołanie operacji, a następnie wykonanie innej czynności warunkowo na podstawie statusu zakończenia operacji. Philippe A. ładnie to wyjaśnił w swojej odpowiedzi na ten post

W bashu i ogólnie w powłokach unixowych wartości zwracane nie są logiczne. Są to całkowite kody wyjścia.

Konieczne jest zatem zinterpretowanie statusu zakończenia tych operacji jako wartości logicznej. Sensowne jest mapowanie 0statusu zakończenia pomyślnego ( ) na wartość true, a statusu wyjścia niezerowego / błędu na fałsz. Dzięki temu możliwe jest warunkowe wykonywanie połączonych poleceń powłoki.

Oto przykład mkdir deleteme && cd $_ && pwd. Ponieważ powłoka interpretuje 0 jako prawdziwe, polecenie to działa zgodnie z oczekiwaniami. Gdyby powłoka zinterpretowała 0 jako fałsz, należałoby odwrócić zinterpretowany kod zakończenia dla każdej operacji.

Krótko mówiąc, interpretacja wartości 0 jako fałszu przez powłokę byłaby bezsensowna, biorąc pod uwagę konwencję, zgodnie z którą aplikacje zwracają 0 dla pomyślnego zakończenia.


[* 1]: Tak, wiele razy operacje muszą zwracać coś więcej niż zwykły komunikat o sukcesie, ale to wykracza poza zakres tego wątku.

Zobacz także Dodatek E w Przewodniku po zaawansowanych skryptach Bash

aksjopatyczny
źródło
2
Witam, chcę tylko podkreślić, że gdyby powłoka interpretowała zero jako fałsz, a niezerowe jako prawdę, sztuczka z robieniem mkdir deleteme && cd _$ && pwdnie zawiodłaby; ale musielibyśmy go zastąpić mkdir deleteme || cd _$ || pwd, co moim zdaniem jest znacznie mniej jasne, ponieważ to, co faktycznie chcemy zrobić, to mkdir deletemeicd _$ipwd… (gdzie „i” ma tutaj znaczenie z języka potocznego).
Rémi Peyre
1
Myślę, że ująłem to w mojej odpowiedzi. Żeby było jasne, kiedy odwracasz logikę, nie wystarczy po prostu zastąpić &&operatorów ||operatorami. Musiałbyś w pełni zastosować prawo De Morgana. Zobacz: en.wikipedia.org/wiki/De_Morgan%27s_laws
axiopisty
1
Inna uwaga: widzę co najmniej trzy powody, dla których, ogólnie rzecz biorąc, naturalne byłoby stwierdzenie, że trueodpowiada zeru i falseodpowiada wartości niezerowej. Po pierwsze, jeśli ci coś powiem, to „powiedziałem ci prawdę” zależy od liczby kłamstw, które powiedziałem: albo jest to zero i powiedziałem (ogólnie) prawdę, albo jest niezerowe i skłamałem. Zasadniczo jest to to samo, co chcemy, aby logika andodpowiadała wspólnemu „i” dodawania (oczywiście przy ograniczaniu się do liczb naturalnych).
Rémi Peyre
1
(kontynuacja z poprzedniego komentarza). Drugi powód jest taki, że jest jedna prawda, ale wiele nieprawd; dlatego wygodniej jest skojarzyć jedyną wartość for truei wszystkie inne wartości for false. (Jest to zasadniczo to samo, co rozważania dotyczące wartości zwracanych przez programy).
Rémi Peyre
(kontynuacja z poprzedniego komentarza). Trzeci powód jest taki, że „prawda że prawda A” jest tym samym co „prawda że A”, „fałsz że fałsz, że A” to to samo co „fałsz że A” itd .; tak, że truezachowuje się jak mnożnik 1 i falsemnożnik -1. Co, jako potęga -1, oznacza, że truezachowuje się dodatkowo jako „parzysta” i false„nieparzysta”. Znowu to truezasługuje na zero ...
Rémi Peyre
17

Najważniejszy punkt, który uważam za ważny do zrozumienia, jest następujący. W bashu i ogólnie w powłokach unixowych wartości zwracane nie są logiczne. Są to całkowite kody wyjścia. W związku z tym należy je oceniać zgodnie z konwencją mówiącą, że 0 oznacza sukces, a inne wartości oznaczają błąd.

Z test, [ ]lub [[ ]]operatorów, warunki bash ocenić jako prawdziwe w przypadku kodu wyjścia 0 (wynik / bin / true). W przeciwnym razie oceniają jako fałszywe.

Ciągi są oceniane inaczej niż kody zakończenia:

if [ 0 ] ; then echo not null ; fi
if [ $(echo 0) ] ; then echo not null ; fi

if [ -z "" ] ; then echo null ; fi

(( ))Operator arytmetyczny interpretuje 1 i 0 jako prawdziwe i fałszywe. Ale że operator nie może być stosowany jako kompletny zamiennik test, [ ]lub [[ ]]. Oto przykład pokazujący, kiedy operator arytmetyczny jest przydatny:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done
Philippe A.
źródło
Dziękuję za wyjaśnienie nawiasów klamrowych i nawiasów na prawda / fałsz
javadba
15

To zwykła konwencja, że ​​kod zakończenia 0 oznacza sukces. EXIT_SUCCESS będzie 0 w prawie każdym nowoczesnym systemie.

EDYTOWAĆ:

„Dlaczego zarówno test 0, jak i test 1 zwracają 0 (sukces)?”

To zupełnie inne pytanie. Odpowiedź jest taka, że ​​przekazanie pojedynczego argumentu do przetestowania zawsze kończy się sukcesem, chyba że ten argument jest łańcuchem pustym („”). Zobacz dokumentację Open Group .

Matthew Flaschen
źródło
Dlaczego więc oba test 0i test 1zwracają 0 (sukces)?
httpinterpret
5
@httpinterpret, testnie testuje wartości liczbowych. Sprawdza, czy ten ciąg jest łańcuchem pustym. man testpo więcej informacji.
Carl Norum
12

Zazwyczaj programy zwracają zero dla sukcesu, niezerowe dla niepowodzenia; falsezwraca 1, ponieważ jest to wygodna wartość niezerowa, ale generalnie każda wartość niezerowa oznacza awarię jakiegoś rodzaju, a wiele programów zwraca różne wartości niezerowe, aby wskazać różne tryby awarii

Michał Mrozek
źródło
2
Głosy przeciwne bez wyjaśnienia (lub oczywistego powodu) są do niczego, a ci, którzy to robią, są kiepscy, ponieważ w ogóle nie pomagają społeczności.
Abdullah Jibaly
1
Nie akceptowanie go ... ale to jest ich 2 punkty ... i @MichaelMrozek .. z 19.6k, nie może zranić tak źle, lol.
Alex Grey
1
@alexgray To było dwa lata temu; wtedy miałem około 5 tys. A ja byłem bardziej zaciekawiony, co jest nie tak z odpowiedzią niż z reprezentantem
Michał Mrozek.
4

jest to konwencja sięgająca wczesnych dni Uniksa.

Zgodnie z konwencją, wszystkie wywołania systemowe zwracają 0, jeśli się powiedzie, a w przeciwnym razie niezerowe, ponieważ wtedy różne liczby mogą być używane do wskazania różnych przyczyn niepowodzenia.

Powłoki przestrzegają tej konwencji, 0 oznacza, że ​​ostatnie polecenie zakończyło się powodzeniem, w przeciwnym razie wartość niezerowa. Podobnie niezerowa wartość zwracana jest przydatna w przypadku komunikatów o błędach wyjściowych: np. 1: „mózg martwy”, 2: „bez serca” i tak dalej.


źródło
To jest odpowiedź.
Peter - Przywróć Monikę
3

Próbujesz utożsamiać prawdę / fałsz z sukcesem / porażką.

Są to dwie całkowicie, choć początkowo subtelne, różne dychotomie!

W skryptach powłoki nie ma czegoś takiego jak prawda / fałsz. „Wyrażenia” powłoki nie są interpretowane jako prawda / fałsz. Raczej „wyrażenia” powłoki to procesy, które kończą się sukcesem lub niepowodzeniem.

Oczywiście proces może się nie powieść z wielu powodów. Dlatego potrzebujemy większego zestawu kodów do mapowania możliwych awarii. Liczby całkowite dodatnie załatwiają sprawę. Z drugiej strony, jeśli proces się powiedzie, oznacza to, że zrobił dokładnie to, co powinien. Ponieważ jest tylko jeden sposób, aby to zrobić, potrzebujemy tylko jednego kodu. 0 załatwia sprawę.

W C tworzymy program. W skrypcie powłoki uruchamiamy kilka programów, aby coś zrobić.

Różnica!

captaincurrie
źródło
To zagmatwane. Wpisz „man [”. Pokazuje Narzędzie testowe ocenia wyrażenie i, jeśli zwróci wartość true, zwraca zerowy (prawdziwy) kod zakończenia; w przeciwnym razie zwraca 1 (fałsz). Jeśli nie ma wyrażenia, test również zwraca 1 (fałsz).
kawalkada
1

Może dobrym sposobem na zapamiętanie tego jest:

  • Kody zwrotne odpowiadają „jaka jest odpowiedź?” prawda (lub inny wynik) lub fałsz
  • Kody zakończenia odpowiadają „w czym problem?” kod wyjścia lub bez problemu (0)
jjisnow
źródło