Istnieje kilka różnic. Moim zdaniem kilka najważniejszych to:
[jest wbudowany w Bash i wiele innych nowoczesnych powłok. Wbudowane [jest podobne do testdodatkowego wymogu zamknięcia ]. W builtins [i testnaśladować funkcjonalność /bin/[i /bin/testwraz z ich ograniczeniami, tak aby skrypty byłoby wstecznie kompatybilne. Oryginalne pliki wykonywalne nadal istnieją głównie dla zgodności z POSIX i kompatybilności wstecznej. Uruchomienie polecenia type [w Bash oznacza, że [domyślnie jest interpretowane jako wbudowane. (Uwaga: which [szuka tylko plików wykonywalnych na ścieżce i jest równoważne type -p [)
[[nie jest tak kompatybilny, niekoniecznie będzie działał z dowolnymi /bin/shpunktami. Podobnie [[jest z bardziej nowoczesną opcją Bash / Zsh / Ksh.
Ponieważ [[jest wbudowany w powłokę i nie ma starszych wymagań, nie musisz się martwić dzieleniem słów na podstawie zmiennej IFS , aby zepsuć zmienne, które mają łańcuch znaków ze spacjami. Dlatego tak naprawdę nie trzeba umieszczać zmiennej w podwójnych cudzysłowach.
W przeważającej części reszta to tylko ładniejsza składnia. Aby zobaczyć więcej różnic, polecam ten link do odpowiedzi na najczęściej zadawane pytania: Jaka jest różnica między testem, [i [[? . W rzeczywistości, jeśli poważnie podchodzisz do skryptów bash, polecam przeczytanie całej wiki , w tym FAQ, pułapek i przewodnika. Sekcja testowa z sekcji przewodnika wyjaśnia również te różnice i dlaczego autor (autorzy) uważają, że [[jest lepszym wyborem, jeśli nie musisz się martwić, że jesteś tak przenośny. Główne powody to:
Nie musisz się martwić o cytowanie lewej strony testu, aby faktycznie został odczytany jako zmienna.
Nie musisz uciekać mniej niż i więcej niż < >z odwrotnymi ukośnikami, aby nie zostały ocenione jako przekierowanie wejściowe, co może naprawdę popsuć niektóre rzeczy przez zastąpienie plików. To znów wraca do [[bycia wbudowanym. Jeśli [(test) jest programem zewnętrznym, powłoka musiałaby zrobić wyjątek w swojej ocenie <i >tylko wtedy, gdy /bin/testzostanie wywołana, co tak naprawdę nie miałoby sensu.
Dzięki, szukałem linku do bash FAQ (nie wiedziałem o tej stronie, dzięki).
0x89,
2
Zredagowałem twój post z tymi informacjami, ale [i test są wykonywane jako wbudowane. Wbudowane zostały zaprojektowane w celu zastąpienia / bin / [i / bin / test, ale musiały również odtworzyć ograniczenia plików binarnych. Polecenie „type [” sprawdza, czy wbudowane jest używane. ”, który [wyszukuje tylko pliki wykonywalne na PATH i jest równoważny z„ type -P [”
klynch
133
W skrócie:
[jest bash Wbudowany
[[]] to słowa kluczowe bash
Słowa kluczowe: słowa kluczowe są podobne do wbudowanych, ale główna różnica polega na tym, że mają do nich zastosowanie specjalne reguły analizy. Na przykład [to wbudowane bash, a [[to słowo kluczowe bash. Oba są używane do testowania rzeczy, ale ponieważ [[jest słowem kluczowym, a nie wbudowanym, korzysta z kilku specjalnych reguł analizy, które znacznie ułatwiają:
$ [ a < b ]-bash: b:No such file or directory
$ [[ a < b ]]
Pierwszy przykład zwraca błąd, ponieważ bash próbuje przekierować plik b do polecenia [a]. Drugi przykład faktycznie robi to, czego się spodziewasz. Znak <nie ma już specjalnego znaczenia dla operatora przekierowywania plików.
[jest poleceniem powłoki POSIX; nie musi być wbudowany. ]jest tylko argumentem, którego szuka ta komenda, aby składnia była zrównoważona. Polecenie jest synonimem, z testwyjątkiem tego, testże nie szuka zamknięcia ].
]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 sposobu, 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, że Xanalizuje się go magicznie. <, &&, ||I ()są traktowane specjalnie, oraz zasady podziału na słowa są różne.
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 wykorzystasz [[ ]]:
stracić przenośność
zmusić czytelnika do poznania zawiłości innego rozszerzenia bash. [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 alub b(jak +lub index) i dokonuje porównania numerycznego, jeśli ai bwyglą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 alub bpodobnych !lub (.
4 w wersji bash 3.2 i nowszej oraz pod warunkiem, że zgodność z wersją bash 3.1 nie jest włączona (jak w przypadku BASH_COMPAT=3.1)
5 chociaż grupowanie (tutaj z {...;}grupą komend zamiast (...)której uruchamiał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.
Jak korzystać z printf 'ab' | grep -Eq 'ab?'wewnątrz if [ … ]?
meeDamian
1
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi. []to polecenie jak grep. To polecenie ()może nie być potrzebne w tym poleceniu. Nie jestem pewien: dodałem je z powodu |, zależy od tego, jak Bash analizuje różne rzeczy. Jeśli nie było |, jestem pewien, że możesz po prostu pisać if cmd arg arg; then.
W oparciu o szybki odczyt odpowiednich sekcji strony podręcznika podstawowa różnica wydaje się polegać na tym, że operatory ==i !=pasują do wzorca, a nie do literału, a także, że istnieje =~operator porównania wyrażeń regularnych.
if
instrukcji, zobacz mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5DOdpowiedzi:
Istnieje kilka różnic. Moim zdaniem kilka najważniejszych to:
[
jest wbudowany w Bash i wiele innych nowoczesnych powłok. Wbudowane[
jest podobne dotest
dodatkowego wymogu zamknięcia]
. W builtins[
itest
naśladować funkcjonalność/bin/[
i/bin/test
wraz z ich ograniczeniami, tak aby skrypty byłoby wstecznie kompatybilne. Oryginalne pliki wykonywalne nadal istnieją głównie dla zgodności z POSIX i kompatybilności wstecznej. Uruchomienie poleceniatype [
w Bash oznacza, że[
domyślnie jest interpretowane jako wbudowane. (Uwaga:which [
szuka tylko plików wykonywalnych na ścieżce i jest równoważnetype -p [
)[[
nie jest tak kompatybilny, niekoniecznie będzie działał z dowolnymi/bin/sh
punktami. Podobnie[[
jest z bardziej nowoczesną opcją Bash / Zsh / Ksh.[[
jest wbudowany w powłokę i nie ma starszych wymagań, nie musisz się martwić dzieleniem słów na podstawie zmiennej IFS , aby zepsuć zmienne, które mają łańcuch znaków ze spacjami. Dlatego tak naprawdę nie trzeba umieszczać zmiennej w podwójnych cudzysłowach.W przeważającej części reszta to tylko ładniejsza składnia. Aby zobaczyć więcej różnic, polecam ten link do odpowiedzi na najczęściej zadawane pytania: Jaka jest różnica między testem, [i [[? . W rzeczywistości, jeśli poważnie podchodzisz do skryptów bash, polecam przeczytanie całej wiki , w tym FAQ, pułapek i przewodnika. Sekcja testowa z sekcji przewodnika wyjaśnia również te różnice i dlaczego autor (autorzy) uważają, że
[[
jest lepszym wyborem, jeśli nie musisz się martwić, że jesteś tak przenośny. Główne powody to:< >
z odwrotnymi ukośnikami, aby nie zostały ocenione jako przekierowanie wejściowe, co może naprawdę popsuć niektóre rzeczy przez zastąpienie plików. To znów wraca do[[
bycia wbudowanym. Jeśli [(test) jest programem zewnętrznym, powłoka musiałaby zrobić wyjątek w swojej ocenie<
i>
tylko wtedy, gdy/bin/test
zostanie wywołana, co tak naprawdę nie miałoby sensu.źródło
W skrócie:
Słowa kluczowe: słowa kluczowe są podobne do wbudowanych, ale główna różnica polega na tym, że mają do nich zastosowanie specjalne reguły analizy. Na przykład [to wbudowane bash, a [[to słowo kluczowe bash. Oba są używane do testowania rzeczy, ale ponieważ [[jest słowem kluczowym, a nie wbudowanym, korzysta z kilku specjalnych reguł analizy, które znacznie ułatwiają:
Pierwszy przykład zwraca błąd, ponieważ bash próbuje przekierować plik b do polecenia [a]. Drugi przykład faktycznie robi to, czego się spodziewasz. Znak <nie ma już specjalnego znaczenia dla operatora przekierowywania plików.
Źródło: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
źródło
[
jest poleceniem powłoki POSIX; nie musi być wbudowany.]
jest tylko argumentem, którego szuka ta komenda, aby składnia była zrównoważona. Polecenie jest synonimem, ztest
wyjątkiem tego,test
że nie szuka zamknięcia]
.Różnice w zachowaniu
Niektóre różnice w Bash 4.3.11:
Rozszerzenie POSIX vs Bash:
[
jest POSIX[[
jest rozszerzeniem Bash¹ udokumentowanym na stronie : https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsregularne 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 sposobu, 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: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword<
[[ a < b ]]
: porównanie leksykograficzne[ a \< b ]
: Jak powyżej.\
wymagane, inaczej przekierowuje jak w przypadku każdego innego polecenia. Rozszerzenie Bash.expr a \< b > /dev/null
: POSIX ekwiwalent², patrz: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
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ładniowy,()
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 5dzielenie 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ładniowy, 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 wzory (* ? [
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 4 , traci magię z''
[[ ab? =~ 'ab?' ]]
: prawdziwe=~
[[ ab =~ ab? ]]
: true, 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 wykorzystasz
[[ ]]
:[
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(
.4 w wersji bash 3.2 i nowszej oraz pod warunkiem, że zgodność z wersją bash 3.1 nie jest włączona (jak w przypadku
BASH_COMPAT=3.1
)5 chociaż grupowanie (tutaj z
{...;}
grupą komend zamiast(...)
której uruchamiał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
printf 'ab' | grep -Eq 'ab?'
wewnątrzif [ … ]
?if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
.[]
to polecenie jakgrep
. To polecenie()
może nie być potrzebne w tym poleceniu. Nie jestem pewien: dodałem je z powodu|
, zależy od tego, jak Bash analizuje różne rzeczy. Jeśli nie było|
, jestem pewien, że możesz po prostu pisaćif cmd arg arg; then
.()
: stackoverflow.com/questions/8965509/...Pojedynczy nawias, tzn.
[]
Jest zgodny z powłoką POSIX, aby zawrzeć wyrażenie warunkowe.Podwójny nawias, tzn.
[[]]
Jest ulepszoną (lub rozszerzoną) wersją standardowej wersji POSIX, obsługiwaną przez bash i inne powłoki (zsh, ksh).W bash, dla porównania numerycznym używamy
eq
,ne
,lt
igt
, z podwójnych nawiasach dla porównania możemy wykorzystać==
,!=
,<,
i>
dosłownie.[
jest synonimem polecenia testowego. Nawet jeśli jest wbudowany w powłokę, tworzy nowy proces.[[
to nowa, ulepszona wersja, która jest słowem kluczowym, a nie programem.na przykład:
źródło
W oparciu o szybki odczyt odpowiednich sekcji strony podręcznika podstawowa różnica wydaje się polegać na tym, że operatory
==
i!=
pasują do wzorca, a nie do literału, a także, że istnieje=~
operator porównania wyrażeń regularnych.źródło