Uczę się o strukturach decyzyjnych i natrafiłem na następujące kody:
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
Oba zachowują się tak samo. Czy są jakieś zalety korzystania z jednej drogi od drugiej?
shell-script
syntax
control-flow
Subhaa Chandar
źródło
źródło
Odpowiedzi:
Nie, konstrukcje
if A; then B; else C; fi
i nieA && B || C
są równoważne .Za pomocą
if A; then B; else C; fi
komendaA
jest zawsze analizowana i wykonywana (przynajmniej podejmowana jest próba jej wykonania), a następnie komendaB
lub komendaC
są oceniane i wykonywane.Dzięki
A && B || C
, to samo dla poleceńA
iB
jednak różne dlaC
: poleceniaC
jest analizowany i wykonywany jeśli obajA
się nie powiedzie lubB
nie.W swoim przykładzie załóżmy, że ci się uda,
chmod u-r ./myfile
pomimo[ -f ./myfile ]
sukcesucat /home/user/myfile
Moja rada: używaj
A && B
lubA || B
ile chcesz, pozostaje to łatwe do odczytania i zrozumienia i nie ma pułapki. Ale jeśli masz na myśli, jeśli ... to ... jeszcze ... wtedy użyjif A; then B; else C; fi
.źródło
Większości ludzi łatwiej jest zrozumieć
if
...then
...else
...fi
formę.Albowiem
a && b || c
, trzeba mieć pewność, żeb
powróci prawda. Jest to przyczyną subtelnych błędów i jest dobrym powodem, aby unikać tego stylu. Jeśli b nie zwróci prawdy, to nie są takie same.W przypadku bardzo krótkich testów i działań, które nie mają klauzuli else, skrócona długość jest atrakcyjna, np
&&
i||
sąshort circuiting operators
, jak tylko wynik będzie znany, dalsze niepotrzebne testy są pomijane.a && b || c
jest zgrupowane jako(a && b) || c
. Pierwszya
jest uruchamiany. Jeślifails
zdefiniowano, że nie zwraca statusu wyjścia 0, grupa(a && b)
jest znanafail
ib
nie trzeba jej uruchamiać.||
Nie wie wynikiem ekspresji więc musi wykonaćc
. Jeśli sięa
powiedzie (zwraca zero),&&
operator nie wie jeszcze wyniku,a && b
więc musi biec,b
aby się dowiedzieć. Jeśli sięb
powiedzie, to sięa && b
powiedzie i||
wie, że ogólny wynik to sukces, więc nie trzeba go uruchamiaćc
. Jeśli to sięb
nie powiedzie||
nadal nie zna wartości wyrażenia, więc musi zostać uruchomionyc
.źródło
Operator && wykonuje następne polecenie, jeśli poprzednie polecenie zakończyło się pomyślnie (zwrócony kod wyjścia ($?) 0 = logiczna prawda).
W formie
A && B || C
polecenie (lub warunek) A jest oceniane, a jeśli A zwróci wartość true (sukces, kod wyjścia 0), wówczas polecenie B zostanie wykonane. Jeśli A nie powiedzie się (w ten sposób zwróci fałsz - kod wyjścia inny niż 0) i / lub B zawiedzie ( zwróci fałsz ), wówczas polecenie C zostanie wykonane.Również
&&
operator jest używany jako AND w sprawdzaniu stanu, a operator||
działa jak OR w sprawdzaniu stanu.W zależności od tego, co chcesz zrobić ze skryptem, formularza
A && B || C
można użyć do sprawdzania warunków, takiego jak twój przykład, lub do połączenia poleceń i zapewnienia serii poleceń do wykonania, jeśli poprzednie polecenia miały kod wyjścia 0 .To dlatego jest często można zauważyć komendy jak:
do_something && do_something_else_that_depended_on_something
.Przykłady:
apt-get update && apt-get upgrade
Jeśli aktualizacja się nie powiedzie, aktualizacja nie zostanie wykonana (ma to sens w prawdziwym świecie ...).mkdir test && echo "Something" > test/file
Część
echo "Something"
zostanie wykonana tylko wtedy, gdymkdir test
zakończy się powodzeniem, a operacja zwróci kod wyjścia 0 ../configure --prefix=/usr && make && sudo make install
Zwykle znajduje się przy kompilowaniu zadań w celu połączenia wymaganych komend zależnych.
Jeśli spróbujesz wdrożyć powyżej „łańcuchy” z czy - następnie - jeszcze trzeba będzie dużo więcej poleceń i kontroli (a więc więcej kodu napisać - więcej rzeczy się nie udać) dla prostego zadania.
Należy również pamiętać, że łańcuchy poleceń zawierają && i || są odczytywane przez powłokę od lewej do prawej. Konieczne może być grupowanie poleceń i sprawdzanie warunków za pomocą nawiasów, aby uzależnić następny krok od pomyślnego wyniku niektórych poprzednich poleceń. Na przykład zobacz to:
Lub przykład z życia:
Należy pamiętać, że niektóre polecenia zwracają różne kody wyjścia w zależności od wykonywanego procesu lub zwracają różne kody w zależności od ich akcji (na przykład polecenie GNU
diff
zwraca 1, jeśli dwa pliki się różnią, a 0, jeśli nie). Takie polecenia należy traktować ostrożnie w && i || .Również po to, aby mieć wszystkie układanki razem, należy pamiętać o łączeniu poleceń za pomocą
;
operatora. W formacieA;B;C
wszystkie polecenia będą wykonywane szeregowo, bez względu na kod wyjścia poleceniaA
iB
.źródło
Wiele zamieszania na ten temat może wynikać z tego, że dokumentacja bash wywołuje te listy AND i OR . Mimo że są logicznie podobne
&&
i||
znajdują się w nawiasach kwadratowych, działają inaczej.Niektóre przykłady najlepiej ilustrują to ...
Jeśli
cmda
wyjście true,cmdb
jest wykonywane.Jeśli
cmda
wyjdzie false,cmdb
NIE zostanie wykonane, alecmdc
zostanie wykonane.Jak
cmda
wyjścia są ignorowane.Jeśli
cmdb
wyjście true,cmdc
jest wykonywane.Jeśli
cmdb
wyjdzie false,cmdc
NIE zostanie wykonane icmdd
jest.Jeśli
cmda
wyjście true,cmdb
jest wykonywane, a następniecmdc
.Jeśli
cmda
wyjdzie false,cmdb
NIE zostanie wykonane, alecmdc
zostanie wykonane.Co? Dlaczego jest
cmdc
wykonywany?Ponieważ dla interpretatora średnik (
;
) i nowa linia oznaczają dokładnie to samo. Bash widzi ten wiersz kodu jako ...Aby osiągnąć oczekiwane, musimy zamknąć
cmdb; cmdc
wewnątrz nawiasów klamrowych, aby uczynić je Poleceniem złożonym (polecenie grupy) . Dodatkowy średnik kończący jest tylko wymogiem{ ...; }
składni. Więc otrzymujemy ...cmda && { cmdb; cmdc; }
Jeśli
cmda
wyjście true,cmdb
jest wykonywane, a następniecmdc
.Jeśli
cmda
wychodzi fałszywa, anicmdb
czycmdc
jest wykonywany.Wykonanie jest kontynuowane od następnego wiersza.
Stosowanie
Listy poleceń warunkowych są najbardziej przydatne do jak najszybszego powrotu z funkcji, a tym samym do unikania interpretacji i wykonywania dużej ilości niepotrzebnego kodu. Wiele zwrotów funkcji oznacza jednak, że trzeba mieć obsesję na punkcie utrzymywania krótkich funkcji, aby łatwiej było zapewnić, że wszystkie możliwe warunki zostaną pokryte.
Oto przykład z działającego kodu ...
źródło