Różnica między pojedynczym i podwójnym nawiasem kwadratowym w Bash

Czytam przykłady Basha o if, ale niektóre przykłady są pisane pojedynczymi nawiasami kwadratowymi:

if [ -f $param ]
then
  #...
fi

Inne z podwójnymi nawiasami kwadratowymi:

if [[ $? -ne 0 ]]
then
    start looking for errors in yourlog
fi

Jaka jest różnica?

Author: codeforester, 2012-11-24

6 answers

Single [] są testami stanu zgodnymi ze standardem posix shell.

Double [[]] są rozszerzeniem standardu [] i są obsługiwane przez bash i inne powłoki (np. zsh, ksh). Obsługują dodatkowe operacje (jak również standardowe operacje posix). Na przykład: || zamiast -o i regex pasujący do =~. Pełniejszą listę różnic można znaleźć w sekcji podręcznika bash dotyczącej konstrukcji warunkowych .

Użyj [] kiedy chcesz, aby twój skrypt był przenośne w poprzek muszli. Użyj [[]], jeśli chcesz, aby wyrażenia warunkowe nie były obsługiwane przez [] i nie muszą być przenośne.

 206
Author: cmh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-24 16:06:32

Różnice w zachowaniu

Testowane w Bash 4.3.11:

  • Rozszerzenie POSIX vs Bash:

  • Zwykłe polecenie vs Magia

    • [ to zwykła Komenda o dziwnej nazwie.

      ] jest po prostu ostatni argument [.

    Ubuntu 16.04 faktycznie ma plik wykonywalny w /usr/bin/[ dostarczony przez coreutils, ale wbudowana wersja bash ma pierwszeństwo.

    Nic nie jest zmieniane w sposób, w jaki Bash przetwarza polecenie.

    W szczególności, < jest przekierowaniem, && i || łączy wiele poleceń, ( ) generuje podshell, o ile nie jest unikalny przez \, a rozszerzenie Worda odbywa się jak zwykle.

    • [[ X ]] jest pojedynczą konstrukcją, która sprawia, że X jest analizowany magicznie. <, &&, || i () są traktowane specjalnie, a zasady dzielenia wyrazów są różne.

      Istnieją również dalsze różnice, takie jak = i =~.

    W języku Bashese: [ jest wbudowanym poleceniem, a {[1] } jest słowem kluczowym: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && i ||

    • [[ a = a && b = b ]]: true, logiczne i
    • [ a = a && b = b ]: błąd składni, && parsed as an and command separator cmd1 && cmd2
    • [ a = a -a b = b ]: odpowiednik, ale deprecated by POSIX3
    • [ a = a ] && [ b = b ]: POSIX i niezawodny odpowiednik
  • (

    • [[ (a = a || a = b) && a = b ]]: false
    • [ ( a = a ) ]: błąd składni, () jest interpretowany jako subshell
    • [ \( a = a -o a = b \) -a a = b ]: odpowiednik, ale () jest przestarzały przez POSIX
    • { [ a = a ] || [ a = b ]; } && [ a = b ] odpowiednik POSIX 5
  • Dzielenie wyrazów i generowanie nazw plików po rozszerzeniach (split+glob)

    • x='a b'; [[ $x = 'a b' ]]: true, quotes not needed
    • x='a b'; [ $x = 'a b' ]: błąd składni, rozszerza się do [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]: błąd składni, jeśli w bieżącym katalogu znajduje się więcej niż jeden plik.
    • x='a b'; [ "$x" = 'a b' ]: odpowiednik POSIX
  • =

    • [[ ab = a? ]]: true, bo to robi dopasowanie wzorca (* ? [ są magiczne). Nie powoduje rozszerzenia glob do plików w bieżącym katalogu.
    • [ ab = a? ]: a? Globus rozszerza się. Więc może być prawda lub FAŁSZ w zależności od plików w bieżący katalog.
    • [ ab = a\? ]: false, not glob
    • = i == są takie same w [ i [[, ale == jest rozszerzeniem Bash.
    • case ab in (a?) echo match; esac: odpowiednik POSIX
    • [[ ab =~ 'ab?' ]]: false4, traci magię z ''
    • [[ ab? =~ 'ab?' ]]: true
  • =~

    • [[ ab =~ ab? ]]: true, POSIX extended regular expression match, ? does not glob expand
    • [ a =~ a ]: błąd składni. Brak odpowiednika bash.
    • printf 'ab\n' | grep -Eq 'ab?': odpowiednik POSIX (tylko dane jednoliniowe)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': odpowiednik POSIX.

Zalecenie : Zawsze używaj [].

Istnieją odpowiedniki POSIX dla każdej [[ ]] konstrukcji, którą widziałem.

Jeśli używasz [[ ]] ty:

  • utrata przenośności
  • zmusić czytelnika do poznania zawiłości innego rozszerzenia bash. [ to zwykłe polecenie z dziwna nazwa, brak specjalnej semantyki.

1 w 1998 roku, w wyniku połączenia dwóch poprzednich części, powstała nowa wersja gry.]}

2 ale nie dla niektórych wartości a lub b (jak + lub index) i porównuje numeryczne, jeśli a i b wyglądają jak liczby dziesiętne. Działa na obie strony.

3 a także nie dla niektórych wartości a lub b jak ! lub (.

4 w bash 3.2 i nowszych i pod warunkiem, że kompatybilność z bash 3.1 nie jest włączona (jak z BASH_COMPAT=3.1)

5 chociaż grupowanie (tutaj z {...;} Grupa poleceń zamiast (...), która uruchamiałaby niepotrzebny subshell) nie jest konieczne jako operatory powłoki || i && (w przeciwieństwie do || i && [[...]] operatorzy lub -o/-a [ operatory) mają jednakowy pierwszeństwo. Więc [ a = a ] || [ a = b ] && [ a = b ] byłoby równoważne.

 98
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-06 09:00:47

Wewnątrz pojedynczych nawiasów do badania stanu (tj. [ ... ]), niektóre operatory, takie jak single =, są obsługiwane przez wszystkie powłoki, podczas gdy użycie operatora == nie jest obsługiwane przez niektóre starsze powłoki.

Wewnątrz podwójnych nawiasów do testu warunków (tj. [[ ... ]]), nie ma różnicy pomiędzy używaniem = lub == w starych lub nowych powłokach.

Edit: powinienem również zauważyć, że: w bash Zawsze używaj podwójnych nawiasów [[... ]] jeśli to możliwe, ponieważ jest to bezpieczniejsze niż pojedyncze wsporniki. Ja zilustruj dlaczego za pomocą następującego przykładu:

if [ $var == "hello" ]; then

Jeśli $ var jest null / empty, to skrypt widzi to:

if [ == "hello" ]; then

Który złamie twój skrypt. Rozwiązaniem jest użycie podwójnych nawiasów lub Zawsze pamiętaj o umieszczaniu cudzysłowów wokół zmiennych ("$var"). Podwójne nawiasy to lepsza praktyka kodowania defensywnego.

 15
Author: sampson-chen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-24 15:59:11

[[ jest słowem kluczowym bash podobnym do (ale potężniejszym niż) polecenia [.

Zobacz

Http://mywiki.wooledge.org/BashFAQ/031 i http://mywiki.wooledge.org/BashGuide/TestsAndConditionals

Jeśli nie piszesz dla POSIX sh, zalecamy [[.

 13
Author: Gilles Quenot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 04:07:24

Możesz użyć podwójnych nawiasów kwadratowych do dopasowania regex, np.:

if [[ $1 =~ "foo.*bar" ]] ; then

(o ile wersja Basha, której używasz, obsługuje tę składnię)

 1
Author: asf107,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-24 15:58:48

Instrukcja Bash mówi:

W przypadku użycia z [[, operatory " " sortują leksykograficznie używając bieżącego ustawienia lokalnego. Polecenie test używa ASCII zamawiam.

(polecenie test jest identyczne z [ ])

 1
Author: user5500105,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-28 23:43:40