Widzę, że mogę
$ [ -w /home/durrantm ] && echo "writable"
writable
lub
$ test -w /home/durrantm && echo "writable"
writable
lub
$ [[ -w /home/durrantm ]] && echo "writable"
writable
Lubię używać trzeciej składni. Czy są one równoważne pod każdym względem i dla wszystkich przypadków negatywnych i skrajnych? Czy są jakieś różnice w przenośności, np. Między bash na Ubuntu i OS X lub starszych / nowszych wersjach bash, np. Przed / po 4.0 i czy oba rozszerzają wyrażenia w ten sam sposób?
shell
posix
test
portability
Michael Durrant
źródło
źródło
[ … ]
porównaniu do[[ … ]]
vstest …
, w tym najczęściej duplikowanym pytaniu są bardziej kompletne odpowiedzi .Odpowiedzi:
[
jest synonimemtest
polecenia i jednocześnie jest wbudowanym bashem i osobnym poleceniem. Ale[[
jest słowem kluczowym bash i działa tylko w niektórych wersjach. Dlatego ze względu na przenośność lepiej jest używać pojedynczego[]
lubtest
źródło
[
jest wbudowany POSIX czy Bash?test
i[
podobnych. Jeśli powłoka może wykonać ocenę samodzielnie, oszczędza to proces i czyni go nieco szybszym, ale wynik musi być taki sam.[
jest zdefiniowane przez POSIX i dlatego jest maksymalnie przenośne (co wydaje się być[
itest
są POSIX . Wydaje się, że nie ma „zalecanego”, choć jedyną różnicą (?), Którą mogę między nimi zauważyć, jest to, żetest
„nie rozpoznaję argumentu„ - ”[jako ogranicznika wskazującego koniec opcji]” (? - sugerując, że „ - „ jest rozpoznawany jako argument za końcem argumentów, dla[
którego i tak nie mogę wymyślić dobrego przypadku testowego. Ale dygresuję. Użyj tego, co zrobisz. IMO,[
wygląda elegancko, aletest
najwyraźniej jest poleceniem)Tak, są różnice. Najbardziej przenośne są
test
lub[ ]
. Oba są częścią specyfikacji POSIXtest
.if ... fi
Konstrukt jest również zdefiniowane przez POSIX i powinny być w pełni przenośne.[[ ]]
Toksh
cecha, która jest również obecny w niektórych wersjachbash
( wszystkie te nowoczesne ), wzsh
być może w innych, ale nie jest obecna wsh
lubdash
lub różnych innych prostszych muszli.Tak, aby skrypty przenośny, użyj
[ ]
,test
lubif ... fi
.źródło
bash
izsh
wspierałem[[
przez bardzo długi czas (bash
dodałem go pod koniec lat 90.,zsh
nie później niż w 2000 r., I byłbym zaskoczony, gdyby kiedykolwiek brakowało wsparcia), więc jest mało prawdopodobne, abyś spotkał się z wersją którejkolwiek z nich[[
. Wystąpienie innej powłoki zgodnej z POSIX (takiej jakdash
) jest znacznie bardziej prawdopodobne.[[
jest to, że rozszerzenia parametrów nie muszą być cytowane:[[-f $file]]
zdarzenie działa, jeśli$file
zawiera znaki spacji.[[ $a =~ ^reg.*exp.*$' ]]
Pamiętaj, że
[] && cmd
to nie to samo, coif .. fi
konstrukcja.Czasami jego zachowanie jest dość podobne i można go użyć
[] && cmd
zamiastif .. fi
. Ale tylko czasami. Jeśli masz więcej niż jedno polecenie do wykonania, jeśli warunek lub musiszif .. else .. fi
zachować ostrożność i sprawdzić logikę.Kilka przykładów:
To nie to samo co
ponieważ jeśli
ls
zawiedzie,echo
zostanie wykonane, co się nie stanieif
.Inny przykład:
to nie to samo co
chociaż ta konstrukcja będzie działać tak samo
Uwaga:
;
echo jest ważne i musi tam być.Wracając do powyższego stwierdzenia, możemy powiedzieć
[] && cmd
== jeśli pierwsze polecenie zakończy się powodzeniem, wykonaj następneif .. fi
== jeśli warunek (który może być również poleceniem testowym), wówczas wykonaj poleceniaWięc dla przenośności pomiędzy
[
i tylko do[[
użytku[
.if
jest kompatybilny z POSIX. Więc jeśli musisz wybierać pomiędzy[
iif
patrzeć na swoje zadanie i oczekiwane zachowanie.źródło
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. Jest nieco bardziej gadatliwy, ale wciąż krótszy niżif...fi
konstrukcja.[
iif
jako podtytuły, ale nie są. To tak naprawdę&&
zastępujeif
.[
wykonuje kod i zwraca status, podobnie jakls
igrep
zrobiłby.if
wykonywanie rozgałęzień w zależności od statusu zwracanego polecenia (instrukcji) podanego po if, może to być dowolne polecenie (instrukcja).&&
wykonuje następną instrukcję tylko wtedy, gdy poprzednia zwróciła 0, podobnie jak prosteif..then..fi
.W rzeczywistości to,
&&
co zastępujeif
, a nietest
:if
instrukcja w skrypcie powłoki sprawdza, czy polecenie zwróciło „pomyślny” (zerowy) status wyjścia; w twoim przykładzie polecenie to[
.Tak więc różnią się tutaj dwie rzeczy: polecenie użyte do uruchomienia testu oraz składnia użyta do wykonania kodu na podstawie wyniku tego testu.
Polecenia testowe:
test
jest znormalizowanym poleceniem do oceny właściwości ciągów i plików; w twoim przykładzie uruchamiasz polecenietest -w /home/durrantm
[
jest aliasem tego polecenia, jednakowo znormalizowanym, który ma obowiązkowy ostatni argument]
, aby wyglądał jak wyrażenie w nawiasach; nie daj się zwieść, to wciąż tylko polecenie (możesz nawet stwierdzić, że twój system ma plik o nazwie/bin/[
)[[
jest rozszerzoną wersją polecenia testowego wbudowaną w niektóre powłoki, ale nie jest częścią tego samego standardu POSIX; zawiera dodatkowe opcje, których nie używasz tutajWyrażenia warunkowe:
&&
Uruchamiający ( znormalizowane o ) wykonuje operację logiczną AND, oceniając dwa polecenia i powrót 0 (który stanowi prawdziwy), jeżeli oba return 0; oceni drugie polecenie tylko wtedy, gdy pierwsze zwróciło zero, więc można go użyć jako zwykłego warunkowegoif ... then ... fi
Konstrukt ( standaryzowany tutaj ) wykorzystuje tę samą metodę oceny „prawdę”, ale pozwala na liście złożonych oświadczeń wthen
klauzuli, zamiast jednego polecenia zapewnianej przez&&
zwarciem i zapewniaelif
ielse
klauzule, które są trudne do napisania używając tylko&&
i||
. Zauważ, że nie ma nawiasów wokół warunku wif
instrukcji .Wszystkie poniższe elementy są jednakowo przenośne i całkowicie równoważne, renderingi Twojego przykładu:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Chociaż poniższe są również równoważne, ale mniej przenośne z powodu niestandardowego charakteru
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
źródło
Aby przenieść, użyj
test
/[
. Ale jeśli nie potrzebujesz przenośności, ze względu na zdrowie psychiczne siebie i innych osób korzystających z twojego skryptu[[
. :)Zobacz także
What is the difference between test, [ and [[ ?
w BashFAQ .źródło
Jeśli chcesz mieć przenośność poza światem podobnym do Bourne'a:
jest najbardziej przenośny. Działa w skorupkach Bourne'a
csh
irc
rodzinach.Byłoby wyjście
"writable"
zamiastwritable
w muszli zrc
rodziną (rc
,es
,akanga
, gdzie"
nie ma specjalnego).nie działałby w powłokach rodzin
csh
lubrc
w systemach, w których nie ma[
polecenia$PATH
(wiadomo, że niektóre mają,test
ale nie mają[
aliasu).działa tylko w skorupach rodziny Bourne.
działa tylko w
ksh
(skąd pochodzi)zsh
ibash
(wszystkie 3 w rodzinie Bourne).Żadne nie działałoby w
fish
powłoce, w której potrzebujesz:lub:
źródło
Mój najważniejszy powodem wyboru albo
if foo; then bar; fi
czyfoo && bar
jest czy kod zakończenia całego polecenia jest ważne.porównać:
z:
Możesz pomyśleć, że robią to samo; jeśli jednak
foo
zawiedzie (lub jest fałszywe, w zależności od twojego punktu widzenia), to w pierwszym przykładzie do_baz nie zostanie wykonany, ponieważ skrypt zostanie zakończony ...set -e
Instruuje powłokę, aby natychmiast zakończyła działanie, jeśli jakakolwiek komenda zwróci fałszywy status. Bardzo przydatne, jeśli robisz rzeczy takie jak:Nie chcesz, aby skrypt kontynuował działanie, jeśli wystąpi błąd z
cd
jakiegokolwiek powodu.źródło
foo
spowoduje przerwania skryptu w obu przypadkach. Jest to szczególny przypadek dlaset -e
(gdy polecenie jest oceniane jako warunek (po lewej stronie niektórych && / || lub w if / while / till / elsif ...). Niepowodzenie opuściłobybar
powłokę w obu przypadkach.cd /some/directory && rm -rf -- *
lubcd /some/directory || exit; rm -rf -- *
(nadal nie usuwa ukrytych plików). Osobiście nie podoba mi się pomysł,set -e
aby nie usprawiedliwiać się pisaniem poprawnego kodu.