Współpracownik stwierdził ostatnio w przeglądzie kodu, że [[ ]]
konstrukt ma być preferowany [ ]
w podobnych konstrukcjach
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
Nie mógł podać uzasadnienia. Czy jest jeden
bash
if-statement
syntax
Leonard
źródło
źródło
[[
tego, kod jest dobry i przejrzysty, ale pamiętaj o tym dniu, kiedy przeniesiesz swoje skrypty do systemu z domyślną powłoką, która nie jest,bash
lubksh
, itp.[
jest brzydszy, nieporęczny, ale działa jakAK-47
w każdej sytuacji.Odpowiedzi:
[[
ma mniej niespodzianek i jest ogólnie bezpieczniejszy w użyciu. Ale nie jest przenośny - POSIX nie określa, co robi i tylko niektóre powłoki go obsługują (oprócz bash, słyszałem, że ksh też to obsługuje). Na przykład możesz to zrobićaby sprawdzić, czy plik istnieje. Ale z
[
, musisz zacytować$b
, ponieważ dzieli argument i rozwija rzeczy takie jak"a*"
(gdzie[[
bierze dosłownie). Ma to również związek z tym, jak[
może być programem zewnętrznym i odbiera swój argument normalnie jak każdy inny program (chociaż może to być także wbudowany program, ale nadal nie ma specjalnej obsługi).[[
ma także kilka innych fajnych funkcji, takich jak dopasowanie wyrażeń regularnych=~
wraz z operatorami, takimi jak są znane w językach podobnych do C. Oto dobra strona na ten temat: Jaka jest różnica między testem,[
a[[
? i testy bashoweźródło
[[ ]]
ale interpretuje to jako takie samo jak[ ]
.#!/bin/sh
ale używam ich,#!/bin/bash
gdy tylko polegam na pewnej funkcji BASH, co oznacza, że nie jest to już przenośna powłoka Bourne'a.Różnice w zachowaniu
Niektóre różnice w Bash 4.3.11:
Rozszerzenie POSIX vs Bash:
[
jest POSIX[[
jest rozszerzeniem Bash ¹regularne dowodzenie kontra magia
[
to zwykłe polecenie o dziwnej nazwie.]
jest tylko argumentem[
który uniemożliwia użycie dalszych argumentów.Ubuntu 16.04 faktycznie ma dla niego plik wykonywalny
/usr/bin/[
podany przez coreutils , ale wersja wbudowana bash ma pierwszeństwo.Nic nie zmienia w sposobie, w jaki Bash analizuje polecenie.
W szczególności
<
jest przekierowywaniem&&
i||
łączeniem wielu poleceń,( )
generuje podpowłoki, chyba że jest to poprzedzone znakiem ucieczki\
, a rozwijanie słów odbywa się jak zwykle.[[ X ]]
to pojedynczy konstrukt, który sprawia, żeX
analizuje się go magicznie.<
,&&
,||
I()
są traktowane specjalnie, oraz zasady podziału na słowa są różne.Istnieją również dalsze różnice, takie jak
=
i=~
.W języku bashese:
[
jest wbudowanym poleceniem 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, inaczej przekierowuje jak w przypadku każdego innego polecenia. Rozszerzenie Bash.expr a \< b > /dev/null
: POSIX ekwiwalent², patrz: Jak testować ciągi leksykograficzne w Bash mniejszym lub równym?&&
i||
[[ a = a && b = b ]]
: prawda, logika i[ a = a && b = b ]
: błąd składniowy,&&
analizowany jako separator poleceń ANDcmd1 && cmd2
[ a = a -a b = b ]
: równoważne, ale przestarzałe 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 ]
: równoważne, ale()
jest przestarzałe przez POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
Odpowiednik POSIX⁵dzielenie słów i generowanie nazw plików po rozwinięciach (split + glob)
x='a b'; [[ $x = 'a b' ]]
: prawda, cytaty nie są potrzebnex='a b'; [ $x = 'a b' ]
: błąd składniowy, 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? ]]
: true, ponieważ dopasowuje wzorce (* ? [
są magiczne). Nie jest rozwijany globalnie do plików w bieżącym katalogu.[ ab = a? ]
:a?
glob rozszerza się. Może być więc prawdą lub fałszem w zależności od plików w bieżącym katalogu.[ ab = a\? ]
: false, 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⁴, traci magię z''
[[ ab? =~ 'ab?' ]]
: prawdziwe=~
[[ ab =~ ab? ]]
: prawda, rozszerzone dopasowanie wyrażeń regularnych POSIX ,?
nie rozwija się globalnie[ a =~ a ]
: błąd składni. Brak odpowiednika bash.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żdego
[[ ]]
konstruktu, który widziałem.Jeśli korzystasz z
[[ ]]
ciebie:[
to zwykłe polecenie o dziwnej nazwie, nie wymaga specjalnej semantyki.¹ Inspirowany równoważnym
[[...]]
konstruktem w skorupie Korna², ale zawodzi w przypadku niektórych wartości
a
lubb
(jak+
lubindex
) i dokonuje porównania numerycznego, jeślia
ib
wygląda jak liczba całkowita dziesiętna.expr "x$a" '<' "x$b"
działa w obu przypadkach.³, a także zawodzi w przypadku niektórych wartości
a
lubb
podobnych!
lub(
.⁴ w wersji bash 3.2 i nowszych oraz pod warunkiem, że zgodność z wersją bash 3.1 nie jest włączona (jak w przypadku
BASH_COMPAT=3.1
)⁵ że ugrupowanie (w tym przypadku z
{...;}
grupy polecenia, a(...)
co byłoby niepotrzebne powłoki w tle), nie jest konieczne, jak||
i&&
powłoki operatorów (w przeciwieństwie do||
i&&
[[...]]
operatorów lub-o
/-a
[
operatorów) mają tę samą siłę. Więc[ a = a ] || [ a = b ] && [ a = b ]
byłoby równoważne.źródło
[
z tych samych powodów.[[ ]]
ma więcej funkcji - proponuję zajrzeć do Advanced Bash Scripting Guide, aby uzyskać więcej informacji, w szczególności sekcję o rozszerzonym poleceniu testu w rozdziale 7. Testy .Nawiasem mówiąc, jak zauważa przewodnik,
[[ ]]
został wprowadzony w ksh88 (wersja powłoki Korn z 1988 roku).źródło
Z którego komparatora, testu, nawiasów lub nawiasów podwójnych jest najszybszy? ( http://bashcurescancer.com )
źródło
[[
może przynieść. Ale potem jestem oldschoolowym pierdnięciem :-)[
itest
chociaż istnieją również wersje zewnętrzne.PS1=...crazy stuff...
i / lub$PROMPT_COMMAND
); dla tych nie chcę żadnego zauważalnego opóźnienia w wykonaniu skryptu.apt-get update
jeśli minęło więcej niż X godzin od ostatniego uruchomienia. To wielka ulga, kiedy można pominąć przenośność na zbyt długiej liście ograniczeń kodu.Jeśli podoba Ci się przewodnik po stylu Google :
Testuj
[
i[[
źródło
[[ -d ~ ]]
zwraca true (co oznacza, że~
został rozwinięty/home/user
). Myślę, że Google powinien być bardziej precyzyjny w pisaniu.Typowa sytuacja, w której nie można użyć,
[[
to skrypt auto.ooling config.ac, nawiasy mają specjalne i inne znaczenie, więc będziesz musiał użyćtest
zamiast[
lub[[
- Zauważ, że test i[
to ten sam program.źródło
[
że zostanie zdefiniowany jako funkcja powłoki POSIX?[[]] podwójne nawiasy klamrowe są nieobsługiwane w niektórych wersjach SunOS i całkowicie nieobsługiwane deklaracje funkcji wewnętrznych przez: GNU bash, wersja 2.02.0 (1) -release (sparc-sun-solaris2.6)
źródło
W skrócie, [[jest lepszy, ponieważ nie rozwidla innego procesu. Żaden nawias ani pojedynczy nawias nie jest wolniejszy niż nawias podwójny, ponieważ wymaga innego procesu.
źródło
type [
aby to zobaczyć.[[
w odróżnieniu od tego[
jest składnią interpretowaną przez interpretera wiersza poleceń bash. W bash spróbuj pisaćtype [[
. unix4linux ma rację, że chociaż klasyczne[
testy powłoki Bourne'a wykreślają nowy proces w celu ustalenia wartości prawdy,[[
składnia (zapożyczona z ksh przez bash, zsh itp.) nie.[
jest ona wbudowana zarówno w Bash, jak i Dash (/bin/sh
we wszystkich dystrybucjach Linuksa pochodzących z Debiana).