Czytam przykłady basha, if
ale niektóre przykłady są zapisane w pojedynczych nawiasach kwadratowych:
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?
bash
if-statement
rkmax
źródło
źródło
Odpowiedzi:
Pojedyncze
[]
to testy stanu zgodne z powłoką POSIX.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 dopasowywanie wyrażeń regularnych z=~
. Pełniejszą listę różnic można znaleźć w sekcji podręcznika basha poświęconej konstrukcjom warunkowym .Używaj
[]
zawsze, gdy chcesz, aby twój skrypt był przenoszony przez powłoki. Użyj,[[]]
jeśli chcesz, aby wyrażenia warunkowe nie były obsługiwane przez[]
i nie muszą być przenośne.źródło
[[ ]]
(np. Bash z#!/bin/bash
lub#!/usr/bin/env bash
), powinieneś użyć opcji przenośnej. Skrypty, które zakładają, że / bin / sh obsługuje takie rozszerzenia, zepsują się w systemach operacyjnych, takich jak ostatnie wydania Debiana i Ubuntu, w których tak nie jest.Różnice w zachowaniu
Testowane w Bash 4.3.11:
Rozszerzenie POSIX vs Bash:
[
jest POSIX[[
to rozszerzenie Bash¹ udokumentowane pod adresem : https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructszwykłe polecenie kontra magia
[
to zwykłe polecenie o dziwnej nazwie.]
jest po prostu argumentem,[
który uniemożliwia użycie dalszych argumentów.Ubuntu 16.04 ma w rzeczywistości plik wykonywalny
/usr/bin/[
dostarczony przez coreutils, ale wersja wbudowana bash ma pierwszeństwo.Nic nie jest zmieniane w sposobie, w jaki Bash analizuje polecenie.
W szczególności
<
jest przekierowaniem&&
i||
konkatenacją wielu poleceń,( )
generuje podpowłoki, chyba że zostanie przed nimi zmieniona\
, a interpretacja słów odbywa się jak zwykle.[[ X ]]
jest pojedynczą konstrukcją, która umożliwiaX
magiczne przetwarzanie.<
,&&
,||
I()
są traktowane specjalnie, oraz zasady podziału na słowa są różne.Istnieją również dalsze różnice, takie jak
=
i=~
.W Bashese:
[
jest poleceniem wbudowanym i[[
jest słowem kluczowym: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword<
[[ a < b ]]
: porównanie leksykograficzne[ a \< b ]
: Tak samo jak powyżej.\
wymagane lub przekierowanie jak w przypadku każdego innego polecenia. Rozszerzenie Bash.expr a \< b > /dev/null
: Odpowiednik POSIX², zobacz: Jak testować ciągi znaków dla leksykograficznego mniejszego lub równego w Bash?&&
i||
[[ a = a && b = b ]]
: prawda, logiczne i[ a = a && b = b ]
: błąd składni,&&
analizowany jako separator polecenia ANDcmd1 && cmd2
[ a = a -a b = b ]
: odpowiednik, ale przestarzały przez POSIX³[ a = a ] && [ b = b ]
: POSIX i niezawodny odpowiednik(
[[ (a = a || a = b) && a = b ]]
: fałszywe[ ( a = a ) ]
: błąd składni,()
jest interpretowany jako podpowłoka[ \( a = a -o a = b \) -a a = b ]
: odpowiednik, ale()
jest przestarzały przez POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
Odpowiednik POSIX 5podział na słowa i generowanie nazw plików po rozwinięciu (split + glob)
x='a b'; [[ $x = 'a b' ]]
: prawda, cytaty nie są potrzebnex='a b'; [ $x = 'a b' ]
: błąd składni, rozwija się do[ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: błąd składni, jeśli w bieżącym katalogu jest więcej niż jeden plik.x='a b'; [ "$x" = 'a b' ]
: Odpowiednik POSIX=
[[ ab = a? ]]
: prawda, ponieważ dopasowuje wzorce (* ? [
są magiczne). Nie rozwija globalnie do plików w bieżącym katalogu.[ ab = a? ]
:a?
glob się rozszerza. Więc może być prawda lub fałsz w zależności od plików w bieżącym katalogu.[ ab = a\? ]
: false, a nie globalna ekspansja=
i==
są takie same w obu[
i[[
, ale==
jest rozszerzeniem Bash.case ab in (a?) echo match; esac
: Odpowiednik POSIX[[ ab =~ 'ab?' ]]
: false 4 , traci magię z''
[[ ab? =~ 'ab?' ]]
: prawdziwe=~
[[ ab =~ ab? ]]
: prawda, dopasowanie rozszerzonego wyrażenia regularnego POSIX ,?
nie rozwija się globalnie[ a =~ a ]
: błąd składni. Brak odpowiednika basha.printf 'ab\n' | grep -Eq 'ab?'
: Odpowiednik POSIX (tylko dane jednowierszowe)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
[[ ]]
ciebie:[
jest zwykłym poleceniem o dziwnej nazwie, bez specjalnej semantyki.¹ Zainspirowany równoważną
[[...]]
konstrukcją w powłoce Korna² ale kończy się niepowodzeniem w przypadku niektórych wartości
a
lubb
(takich jak+
lubindex
) i porównuje liczbowo, jeślia
ib
wygląda jak dziesiętne liczby całkowite.expr "x$a" '<' "x$b"
działa wokół obu.³ i również zawodzi w przypadku niektórych wartości
a
lubb
podobnych!
lub(
.4 w bash 3.2 i nowszych i pod warunkiem, że kompatybilność z bash 3.1 nie jest włączona (jak w
BASH_COMPAT=3.1
)5 chociaż grupowanie (tutaj z
{...;}
grupą poleceń zamiast(...)
której uruchomiłaby niepotrzebną podpowłokę) nie jest konieczne, ponieważ operatory||
i&&
powłoki (w przeciwieństwie do operatorów||
i&&
[[...]]
lub operatorów-o
/-a
[
) mają równy priorytet. Więc[ a = a ] || [ a = b ] && [ a = b ]
byłoby równoważne.źródło
[]
należy odczytywać jako Moje preferencje : używaj,[]
jeśli nie chcesz stracić przenośności . Jak stwierdzono tutaj : Jeśli problemem jest przenośność / zgodność z POSIX lub BourneShell, należy użyć starej składni. Jeśli z drugiej strony skrypt wymaga BASH, Zsh lub KornShell, nowa składnia jest zwykle bardziej elastyczna, ale niekoniecznie kompatybilna wstecz. Wolę pójść z,[[ ab =~ ab? ]]
jeśli mogę i nie martwię się o kompatybilność wsteczną niżprintf 'ab' | grep -Eq 'ab?'
W nawiasach pojedynczych dla testu warunków (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 badania stanu (tj. [...]]) nie ma różnicy między użyciem
=
lub==
w starych lub nowych powłokach.Edycja: 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. Zilustruję dlaczego na następującym przykładzie:
jeśli zmienna $ var ma wartość null / jest pusta, skrypt widzi to:
co zepsuje twój skrypt. Rozwiązaniem jest użycie podwójnych nawiasów kwadratowych lub zawsze pamiętaj o umieszczaniu zmiennych w cudzysłowie (
"$var"
). Podwójne nawiasy to lepsza metoda obronnego kodowania.źródło
[[
jest słowem kluczowym bash podobnym (ale silniejszym niż) do[
polecenia.Widzieć
http://mywiki.wooledge.org/BashFAQ/031 i http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
Jeśli nie piszesz dla POSIX sh, zalecamy
[[
.źródło
możesz użyć podwójnych nawiasów kwadratowych do lekkiego dopasowywania wyrażeń regularnych, np .:
if [[ $1 =~ "foo.*bar" ]] ; then
(o ile wersja basha, której używasz, obsługuje tę składnię)
źródło
Instrukcja Bash mówi:
(Polecenie testowe jest takie samo jak [])
źródło