Jestem trochę zdezorientowany, co te operatory robią inaczej, gdy są używane w bash (nawiasy, podwójne nawiasy, nawiasy i podwójne nawiasy).
[[ , [ , ( , ((
Widziałem, jak ludzie używają ich, jeśli takie stwierdzenia:
if [[condition]]
if [condition]
if ((condition))
if (condition)
Odpowiedzi:
if
Oświadczenie zazwyczaj wyglądathen
Klauzula jest wykonywany, jeżeli kod wyjściacommands1
wynosi zero. Jeśli kod wyjścia jest niezerowy,else
klauzula jest wykonywana.commands1
może być prosty lub złożony. To może być, na przykład, sekwencji z jednej lub więcej rur, oddzielonych przez jedną z operatorów;
,&
,&&
lub||
. Przedstawioneif
poniżej warunki to tylko szczególne przypadkicommands1
:if [ condition ]
Jest to tradycyjne
test
polecenie powłoki . Jest dostępny we wszystkich powłokach POSIX. Polecenie testowe ustawia kod wyjścia, aif
instrukcja działa odpowiednio. Typowe testy sprawdzają, czy plik istnieje, czy jedna liczba jest równa drugiej.if [[ condition ]]
Jest to nowa ulepszona odmiana
test
od ksh, która obsługuje także bash i zsh . Totest
polecenie ustawia także kod wyjścia, aif
instrukcja działa odpowiednio. Wśród rozszerzonych funkcji może sprawdzać, czy łańcuch pasuje do wyrażenia regularnego.if ((condition))
Kolejne rozszerzenie ksh, które obsługuje także bash i zsh . Wykonuje arytmetykę. W wyniku arytmetyki ustawiany jest kod wyjścia i
if
instrukcja działa odpowiednio. Zwraca kod wyjścia równy zero (prawda), jeśli wynik obliczeń arytmetycznych jest niezerowy. Na przykład[[...]]
ten formularz nie jest POSIX i dlatego nie jest przenośny.if (command)
Uruchamia to polecenie w podpowłoce. Po zakończeniu komendy ustawia kod wyjścia, a
if
instrukcja działa odpowiednio.Typowym powodem korzystania podpowłoce jak to jest ograniczenie skutków ubocznych
command
, jeślicommand
wymagane zmienne zadania lub inne zmiany w środowisku powłoki. Takie zmiany nie pozostaną po zakończeniu podpowłoki.if command
polecenie jest wykonywane, a
if
instrukcja działa zgodnie z kodem wyjścia.źródło
[
tak naprawdę jest to binarne, a nie wewnętrzne polecenie lub symbol. Na ogół mieszka w/bin
.[
jest wbudowanytest
. Dostępne są wersje binarne ze względu na kompatybilność. Sprawdźhelp [
ihelp test
.$((
tzn. Rozszerzenie arytmetyki jest i łatwo je pomylić. Często można obejść ten[ $((2+2)) -eq 4 ]
problem, używając arytmetyki w instrukcjach warunkowychif echo; then echo; fi
.(…)
nawiasy oznaczają podpowłokę . To, co jest w nich, nie jest wyrażeniem jak w wielu innych językach. To lista poleceń (podobnie jak poza nawiasami). Te polecenia są wykonywane w osobnym podprocesie, więc żadne przekierowanie, przypisanie itp. Wykonane w nawiasach nie ma wpływu poza nawiasami.$(…)
jest podstawienie polecenia : w nawiasach znajduje się polecenie, a dane wyjściowe polecenia są używane jako część wiersza polecenia (po dodatkowych rozwinięciach, chyba że podstawienie występuje między podwójnymi cudzysłowami, ale to inna historia ) .{ … }
nawiasy klamrowe są jak nawiasy, ponieważ grupują polecenia, ale wpływają tylko na parsowanie, a nie na grupowanie. Programx=2; { x=4; }; echo $x
wypisuje 4, podczas gdyx=2; (x=4); echo $x
wypisuje 2. (Nawiasy klamrowe będące słowami kluczowymi należy oddzielić i znaleźć w pozycji polecenia (stąd spacja za{
i;
przed}
), podczas gdy nawiasy nie. To tylko dziwactwo składniowe.)${VAR}
jest rozszerzeniem parametru , rozwijającym się do wartości zmiennej, z możliwymi dodatkowymi przekształceniami.ksh93
Powłoka wspomaga również${ cmd;}
w postaci podstawienia poleceń, które nie tarło podpowłokę.((…))
podwójne nawiasy otaczają instrukcję arytmetyczną , czyli obliczanie liczb całkowitych, ze składnią podobną do innych języków programowania. Ta składnia jest najczęściej używana do przypisań i warunków. To istnieje tylko w ksh / bash / zsh, a nie w zwykłym sh.$((…))
, które rozwijają się do wartości całkowitej wyrażenia.[ … ]
pojedyncze nawiasy otaczają wyrażenia warunkowe . Wyrażenia warunkowe są w większości oparte na operatorach, takich jak-n "$variable"
testowanie, czy zmienna jest pusta i-e "$file"
testowanie, czy plik istnieje. Pamiętaj, że potrzebujesz spacji wokół każdego operatora (np.[ "$x" = "$y" ]
Nie) oraz spacji lub znaku, takiego[ "$x"="$y" ]
;
jak wewnątrz i na zewnątrz nawiasów kwadratowych (np.[ -n "$foo" ]
Nie).[-n "$foo"]
[[ … ]]
podwójne nawiasy kwadratowe są alternatywną formą wyrażeń warunkowych w ksh / bash / zsh z kilkoma dodatkowymi funkcjami, na przykład możesz napisać,[[ -L $file && -f $file ]]
aby sprawdzić, czy plik jest dowiązaniem symbolicznym do zwykłego pliku, podczas gdy pojedyncze nawiasy wymagają[ -L "$file" ] && [ -f "$file" ]
. Zobacz Dlaczego interpretacja parametrów ze spacjami bez cudzysłowów działa w podwójnych nawiasach [[ale nie w pojedynczych nawiasach [? więcej na ten temat.W powłoce każde polecenie jest poleceniem warunkowym: każde polecenie ma status zwracany, który wynosi 0, co oznacza sukces lub liczbę całkowitą od 1 do 255 (i potencjalnie więcej w niektórych powłokach), co wskazuje na niepowodzenie.
[ … ]
Polecenie (lub[[ … ]]
forma składni) jest określone polecenie, które mogą być pisanetest …
i uda, jeśli istnieją plików, lub gdy łańcuch nie jest pusty lub, gdy liczba jest mniejsza niż druga itp((…))
postać składni udaje się, gdy liczba jest niezerowy. Oto kilka przykładów warunkowych w skrypcie powłoki:Sprawdź, czy
myfile
zawiera ciąghello
:Jeśli
mydir
jest to katalog, przejdź do niego i wykonaj następujące czynności:Sprawdź, czy
myfile
w bieżącym katalogu znajduje się plik :To samo, ale także z wiszącymi dowiązaniami symbolicznymi:
Sprawdź, czy wartość
x
(która przyjmuje się, że jest liczbowa) wynosi co najmniej 2, przenośnie:Sprawdź, czy wartość
x
(która przyjmuje się, że jest liczbowa) wynosi co najmniej 2, w bash / ksh / zsh:źródło
-a
zamiast&&
, więc można napisać:,[ -L $file -a -f $file ]
która jest taką samą liczbą znaków w nawiasach bez dodatkowych[
i]
...-a
i-o
są problematyczne, ponieważ mogą prowadzić do niepoprawnych analiz, jeśli niektóre z operandów wyglądają jak operatory. Dlatego ich nie wspominam: mają zerową przewagę i nie zawsze działają. I nigdy nie pisz niecytowanych rozszerzeń zmiennych bez uzasadnionego powodu:[[ -L $file -a -f $file ]]
jest w porządku, ale potrzebujesz pojedynczych nawiasów[ -L "$file" -a -f "$file" ]
(co jest dobre, np. Jeśli$file
zawsze zaczyna się od/
lub./
).[[ -L $file && -f $file ]]
(nie-a
z[[...]]
wariantem).Z dokumentacji bash :
Innymi słowy, upewniasz się, że cokolwiek dzieje się na „liście” (jak a
cd
), nie ma wpływu poza(
i)
. Jedyną rzeczą, która będzie przeciekać jest kod zakończenia ostatniego polecenia lub zset -e
pierwszego polecenia, który generuje błąd (inne niż kilka, takich jakif
,while
itp)To rozszerzenie bash pozwala na matematykę. Jest to nieco podobne do używania
expr
bez wszystkich ograniczeńexpr
(takich jak wszędzie spacje, ucieczka*
itp.)To oferuje zaawansowany test do porównywania ciągów, liczb i plików, trochę jak
test
oferty, ale bardziej wydajny.Ten dzwoni
test
. W rzeczywistości w dawnych czasach[
istniał symboliczny link dotest
. Działa tak samo i masz te same ograniczenia. Ponieważ plik binarny zna nazwę, z którą został uruchomiony, program testowy może analizować parametry, dopóki nie znajdzie parametru]
. Zabawne sztuczki uniksowe.Należy pamiętać, że w przypadku
bash
,[
itest
są wbudowane funkcje (jak wspomniano w komentarzu), jeszcze dość dużo obowiązują te same ograniczenia.źródło
test
i[
są oczywiście wbudowanymi poleceniami w Bash, ale prawdopodobnie istnieje również zewnętrzny plik binarny.[
nie jest dowiązaniem symbolicznym dotest
większości nowoczesnych systemów.strings /usr/bin/test
pokazuje, że ma także tekst pomocy, więc nie wiem, co powiedzieć.test
polecenie to oczywiście musi istnieć jako samodzielne polecenie oparte na pliku przez standard, nic w nim nie stwierdza, że jego[
wariant również musi zostać zaimplementowany w ten sposób. Na przykład Solaris 11 nie zapewnia żadnych[
plików wykonywalnych, ale mimo to jest w pełni zgodny ze standardami POSIX[
vs[[
Ta odpowiedź obejmie
[
vs[[
podzbiór kwestii.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
expr
do odpowiedzi. Termin „rozszerzenie Bash” nie ma sugerować, że Bash był pierwszą powłoką, która dodała jakąś składnię. Uczenie się POSIX sh vs. Bash już wystarcza, by doprowadzić mnie do szaleństwa.man test
czy próbowałeśman [
i zgubiłeś się. To wyjaśni wariant POSIX.Kilka przykładów:
Tradycyjny test:
test
i[
są komendami jak wszystkie inne, więc zmienna jest podzielona na słowa, chyba że jest w cudzysłowie.Test w nowym stylu
[[ ... ]]
jest (nowszą) specjalną konstrukcją powłoki, która działa nieco inaczej, najbardziej oczywistą rzeczą jest to, że nie dzieli zmiennych na słowa:Trochę dokumentacji tutaj
[
i[[
tutaj .Test arytmetyczny:
Polecenia „normalne”:
Wszystkie powyższe działają jak normalne polecenia i
if
mogą przyjmować dowolne polecenia:Wiele poleceń:
Lub możemy użyć wielu poleceń. Zawijanie zestawu poleceń
( ... )
uruchamia je w podpowłoce, tworząc tymczasową kopię stanu powłoki (katalog roboczy, zmienne). Jeśli musimy tymczasowo uruchomić jakiś program w innym katalogu:źródło
Polecenia grupowania
( list )
Umieszczenie listy poleceń między nawiasami powoduje utworzenie środowiska podpowłoki i wykonanie każdego z poleceń na liście w tej podpowłoce. Ponieważ lista jest wykonywana w podpowłoce, przypisania zmiennych nie pozostają aktywne po zakończeniu podpowłoki.{ list; }
Umieszczenie listy poleceń między nawiasami klamrowymi powoduje, że lista jest wykonywana w bieżącym kontekście powłoki . Nie jest tworzona podpowłoka. Wymagana jest następująca lista średników (lub znaków nowej linii). ŹródłoKonstrukcje warunkowe
Pojedynczy nawias, tzn.
[]
Do porównania
==, !=, <,
i>
powinien być używany oraz do porównywania numerycznegoeq, ne,lt
igt
powinien być używany.Ulepszone wsporniki tj
[[]]
We wszystkich powyższych przykładach użyliśmy tylko pojedynczych nawiasów, aby zawrzeć wyrażenie warunkowe, ale bash pozwala na podwójne nawiasy, które służą jako ulepszona wersja składni pojedynczego nawiasu.
Dla porównania
==, !=, <,
i>
można używać 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.[[
jest rozumiany przezKorn
iBash
.Źródło
źródło