Dlaczego polecenie „wzór” || prawda ”przydatne?

78

Obecnie badam pakiety Debiana i czytam kilka przykładów kodu. Na przykład w każdym wierszu postinstskryptu jest wzorzec.

some command || true
another command || true

Więc jeśli jakieś polecenie się nie powiedzie, wówczas linia zwraca true, ale nie widzę, jak wpływa to na wynik programu.

Cieśla
źródło
5
FYI, ||:to kolejny idiomatyczny sposób pisania tego ( :jest to kolejny wpis we wbudowanej tabeli wskazujący na true- ale gwarantowany, że jest wbudowany nawet z powrotem do Bourne; to powiedziawszy, dla POSIX sh truerównież jest zagwarantowane, że jest wbudowany - więc jest to więcej zwięzłości niż wydajności w czasach nawet współczesnych).
Charles Duffy,

Odpowiedzi:

151

Przyczyną tego wzorca jest to, że skrypty opiekuna w pakietach Debiana zwykle zaczynają się od set -e, co powoduje, że powłoka kończy działanie, gdy tylko dowolne polecenie (ściśle mówiąc, potok, lista lub polecenie złożone) ma status niezerowy. Dzięki temu błędy się nie kumulują: gdy tylko coś pójdzie nie tak, skrypt przerywa działanie.

W przypadkach, gdy wykonanie polecenia w skrypcie może się nie powieść, dodanie || truepowoduje, że wynikowe polecenie złożone zawsze kończy działanie ze statusem zero, więc skrypt nie przerywa działania. Na przykład usunięcie katalogu nie powinno być krytycznym błędem (uniemożliwiającym usunięcie pakietu); więc skorzystalibyśmy

rmdir ... || true

ponieważ rmdirnie ma opcji, aby ignorować błędy.

Stephen Kitt
źródło
4
Cóż, bez set -epotrzeby || true, pomyślałem, że ważne jest podanie kontekstu. Jeśli zauważysz dziwne rzeczy na POWER, gorąco zachęcam do zgłaszania błędów ( reportbug)!
Stephen Kitt
16
@MichaelFelt, tak naprawdę set -ejest nie tylko „konwencją Debiana”, ale dobrym wzorcem programowania, którego należy zawsze używać. Widzieć. np davidpashley.com/articles/writing-robust-shell-scripts
Kay
2
na pytanie tutaj - dlaczego użycie || truezestawu -e jest prawdopodobnym kontekstem i najprawdopodobniej najczęstszym. Kłaniam się tej odpowiedzi! Dosłownie jest to przydatne, gdy status wyjścia jest uważany za nieistotny ORAZ (jak dodajesz link do artykułu) Nie używam statusu wyjścia jako części mojej kontroli skryptu. Widzę narzędzie (w set -e), ale nie posunęłoby się tak daleko, jak artykuł i powiedział: „Każdy skrypt, który piszesz, powinien zawierać zestaw -e na górze”. To styl programowania. „ZAWSZE | Każdy” zawiera własny zestaw pułapek - aka - absolut absolutny: rozwiązania z dziką kartą w ALWAYSkońcu zwrócą się aka - żadnych bezpłatnych przejazdów.
Michael Felt
1
@Kay Jest to obecnie popularna perspektywa, ale ostatecznie oparła się na licznych założeniach, które ograniczają przenośność skryptu. Istnieją historyczne niespójności z set -ezachowaniem. Może to nie mieć znaczenia, jeśli twoim jedynym celem są bashinne, względnie nowe powłoki, w których żyjesz /bin/sh, ale sytuacja jest bardziej niuansowa, gdy chcesz obsługiwać stare powłoki / systemy.
mtraceur
2
@StephenKitt Pewnie. Istnieje bardzo dokładna strona dokumentująca różne set -ezachowania muszli autorstwa Svena Maschecka , choć strona ta dokumentuje również wiele historycznych / starożytnych powłok, które nie mają dziś znaczenia. Są też te dwie strony o węższym, nowoczesnym wydaniu (wyszukaj „set -e”): strona „lintsh” , dokumentacja przenośnej powłoki autoconf -> podstrona Ograniczenie wbudowanych
mtraceur
32

Chociaż nie wpływa to na wynik działania programu, po prostu uruchom - pozwala wywołującemu kontynuować działanie, jakby wszystko było w porządku, inaczej wpływa na przyszłą logikę.

Przeformułowano: maskuje status błędu poprzedniego polecenia.

michael@x071:[/usr/sbin]cat /tmp/false.sh
#!/bin/sh
false

michael@x071:[/usr/sbin]cat /tmp/true.sh 
#!/bin/sh
false || true

michael@x071:[/usr/sbin]sh /tmp/false.sh; echo $?
1
michael@x071:[/usr/sbin]sh /tmp/true.sh; echo $? 
0
Michael Felt
źródło
6
To prawda, ale nie odpowiada, dlaczego maskowanie statusu wyjścia polecenia jest przydatne.
moopet
4
set -e oznacza, że ​​skrypt natychmiast zakończy działanie po niezerowym zwrocie. W tym zlokalizowanym miejscu możesz nie chcieć, aby tak się działo!
rackandboneman
Jestem prostą osobą - i dla mnie jedynym powodem maskowania statusu błędu jest to, że „przeszkadza”. zestaw -e robi błąd „w drodze”, jeśli wcześniej nie dbałeś o to. Podoba mi się ta dyskusja, ponieważ uważam ją za dobry sposób na debugowanie skryptów i napisanie dodatkowej logiki, aby zareagować na błąd (np. || print - „xxx istniało tutaj niezerowe”. Bardziej prawdopodobne jest, że mam funkcja powłoki „fatal” i mam „coś || fatal” „nieszczęśliwego mnie”. imho skrypt powinien zgłosić nieudany status, lub go nie obchodzi. -e plus || true to maskowanie błędów. Jeśli tego właśnie chcę - dobrze, jeśli nie, brakuje mi błędów
Michael Felt
muszę zadać sobie pytanie: jest || true - kula do kodowania (leniwy sposób na obejście / ominięcie błędu, z którym nie chcę sobie teraz poradzić; narzędzie do debugowania (-e, ale nie || prawda) lub po prostu czyjś dogmat o tym, czym jest dobra praktyka kodowania. Innymi słowy - Widzę to jako cechę - z potencjalną korzyścią. Nie widzę jej jako magicznej różdżki do leczenia wszystkich. Krótko mówiąc - tak jak piękno jest w oku patrzącego - set -ea || trueużyteczność zostanie określona przez cechy i cele programista
Michael Felt
6
@MichaelFelt Zastanów się: git remote remove foo || true git remote add foo http://blah- chcemy zignorować błąd, jeśli pilot nie istnieje.
immibis,