Sunt puțin confuz cu privire la ce fac acești operatori diferit atunci când folosit în bash (paranteze, paranteze duble, paranteză și paranteză dublă).
[[ , [ , ( , ((
Am văzut că oamenii le folosesc dacă afirmații de genul acesta:
if [[condition]] if [condition] if ((condition)) if (condition)
Comentarii
- În legătură: utilizând paranteză simplă sau dublă – bash
- Parantezele și parantezele nu sunt ‘ atât de ușor de căutat în documentație și că ‘ este tot ce aveți dacă nu ‘ nu cunoașteți numele acelor caracteristici.
Răspundeți
În cochilii de tip Bourne, o declarație if
arată de obicei ca
if command-list1 then command-list2 else command-list3 fi
Clauza then
este executată dacă codul de ieșire al lista de comenzi este zero. Dacă codul de ieșire este diferit de zero, atunci se execută clauza else
. command-list1
poate fi simplu sau complex. Poate fi, de exemplu, o secvență de una sau mai multe conducte separate de unul dintre operatorii ;
, &
, &&
, ||
sau linie nouă. Condițiile if
prezentate mai jos sunt doar cazuri speciale de command-list1
:
-
if [ condition ]
[
este un alt nume pentru comanda tradiționalătest
.[
/test
este un utilitar POSIX standard. Toate shell-urile POSIX îl au încorporat (deși „nu este necesar de POSIX²). Comandatest
setează un cod de ieșire și declarațiaif
acționează în consecință. Testele tipice sunt dacă există un fișier sau dacă un număr este egal cu altul. -
if [[ condition ]]
Aceasta este o nouă variantă actualizată pentru
test
¹ din ksh care bash , zsh , yash , busybox sh acceptă, de asemenea. Această construcție[[ ... ]]
stabilește, de asemenea, un cod de ieșire șiif
acționează în consecință. Printre caracteristicile sale extinse, poate testa dacă un șir se potrivește cu un model cu caractere wildcard (nu în busybox sh ). -
if ((condition))
O altă extensie ksh acceptată de bash și zsh . Aceasta efectuează aritmetica. Ca rezultat al aritmeticii, este setat un cod de ieșire și declarația
if
acționează rdingly. Returnează un cod de ieșire zero (adevărat) dacă rezultatul calculului aritmetic este diferit de zero. La fel ca[[...]]
, acest formular nu este POSIX și, prin urmare, nu este portabil. -
if (command)
Aceasta execută comanda într-un sub-shell. Când comanda este finalizată, setează un cod de ieșire și declarația
if
acționează în consecință.Un motiv tipic pentru utilizarea unui subshell ca acesta este limitarea efectelor secundare ale
command
dacăcommand
necesită atribuiri variabile sau alte modificări ale mediului shell-ului. Astfel de modificări nu rămân după finalizarea sub-shell-ului. -
if command
comanda este executată și declarația
if
acționează conform codului său de ieșire.
¹ deși nu este într-adevăr o comandă, ci o construcție specială de shell cu propria sintaxă separată de cea a comenzii normale, și variază semnificativ între implementările shell
² POSIX necesită existența unui test
și [
utilități pe sistem, totuși, deși în cazul [
, mai multe distribuții Linux au fost cunoscute ca fiind m emiterea acestuia.
Comentarii
- Vă mulțumim că ați inclus cea de-a 5-a opțiune. Aceasta ‘ este cheia pentru a înțelege cum funcționează efectiv și este surprinzător de subutilizată.
- Rețineți că
[
este binar, nu o comandă sau un simbol intern. În general locuiește în/bin
. - @JulienR. de fapt
[
este un built-in, la fel ca șitest
. Există versiuni binare disponibile din motive de compatibilitate. Verificațihelp [
șihelp test
. - Merită menționat faptul că while ((isnt POSIX,
$((
adică expansiunea aritmetică este ușoară și este ‘ confundată. Deseori, o soluție este să folosiți ceva de genul[ $((2+2)) -eq 4 ]
pentru a folosi aritmetica în enunțurile conditinale - Aș vrea să votez în sus acest răspuns de mai multe ori. Explicație perfectă.
Răspuns
-
(…)
paranteze indică un subshell . Ceea ce este în interiorul lor nu este o expresie ca în multe alte limbi. „Este o listă de comenzi (la fel ca parantezele exterioare). Aceste comenzi sunt executate într-un subproces separat, astfel încât orice redirecționare, atribuire etc. efectuată în interiorul parantezelor nu are efect în afara parantezelor.- Cu un semn de dolar,
$(…)
este o substituire de comandă : există o comandă în paranteze și ieșirea din comandă este folosit ca parte a liniei de comandă (după extinderi suplimentare, cu excepția cazului în care substituirea este între ghilimele duble, dar „s altă poveste ).
- Cu un semn de dolar,
-
{ … }
paranteze sunt ca paranteze prin faptul că grupează comenzi, dar influențează doar analiza, nu gruparea. Programulx=2; { x=4; }; echo $x
tipărește 4, în timp cex=2; (x=4); echo $x
tipărește 2. (De asemenea, parantezele care sunt cuvinte cheie trebuie delimitate și găsit în poziția de comandă (de aici spațiul după{
și;
înainte de}
) întrucât parantezele nu sunt „t. Asta” este doar o simplă sintaxă.)- Cu un semn de dolar principal,
${VAR}
este un extinderea parametrilor , extinzându-se la valoarea unei variabile, cu posibile transformări suplimentare. Shell-ulksh93
acceptă, de asemenea,${ cmd;}
ca formă de înlocuire a comenzilor care nu generează un subshell.
- Cu un semn de dolar principal,
-
((…))
paranteze duble înconjoară o instrucțiune aritmetică , adică un calcul pe numere întregi, cu o sintaxă care seamănă cu alte limbaje de programare. Această sintaxă este folosită mai ales pentru atribuiri și condiționare. Aceasta există doar în ksh / bash / zsh, nu în sh simplu.- Aceeași sintaxă este utilizată în expresiile aritmetice
$((…))
, care se extind la valoarea întreagă a expresiei.
- Aceeași sintaxă este utilizată în expresiile aritmetice
-
[ … ]
paranteze unice surround expresii condiționale . Expresiile condiționale sunt construite în mare parte pe operatori , cum ar fi-n "$variable"
pentru a testa dacă o variabilă este goală și-e "$file"
pentru a testa dacă există un fișier. Rețineți că aveți nevoie de un spațiu în jurul fiecăruia operator (de ex.[ "$x" = "$y" ]
, nu[ "$x"="$y" ]
;
atât în interiorul, cât și în exteriorul parantezelor (de exemplu,[ -n "$foo" ]
, nu[-n "$foo"]
-
[[ … ]]
parantezele duble sunt o formă alternativă de expresii condiționale în ksh / bash / zsh cu câteva caracteristici suplimentare, de exemplu puteți scrie[[ -L $file && -f $file ]]
pentru a testa dacă un fișier este o legătură simbolică către un fișier obișnuit, în timp ce parantezele simple necesită[ -L "$file" ] && [ -f "$file" ]
. Consultați De ce funcționează extinderea parametrilor cu spații fără ghilimele între paranteze duble [[dar nu paranteze simple [? ] pentru mai multe despre acest subiect.
În shell, comanda fiecare este o comandă condițională: fiecare comandă are o stare de returnare care este fie 0 indicând succesul, fie un număr întreg între 1 și 255 (și potențial mai mult în unele shell-uri) indicând eșec. Comanda [ … ]
(sau forma de sintaxă [[ … ]]
) este o comandă specială care poate fi scrisă și test …
și reușește atunci când există un fișier sau când un șir nu este gol sau când un număr este mai mic decât altul etc. Forma de sintaxă ((…))
reușește atunci când un număr este zero .Iată câteva exemple de condiționare într-un script shell:
-
Testați dacă
myfile
conține șirulhello
:if grep -q hello myfile; then …
-
Dacă
mydir
este un director, schimbați în faceți și faceți lucruri:if cd mydir; then echo "Creating mydir/myfile" echo "some content" >myfile else echo >&2 "Fatal error. This script requires mydir to exist." fi
-
Testați dacă există un fișier numit
myfile
în directorul curent:if [ -e myfile ]; then …
-
La fel, dar inclusiv și legături simbolice suspendate:
if [ -e myfile ] || [ -L myfile ]; then …
-
Testați dacă valoarea
x
(care se presupune că este numerică) este de cel puțin 2, portabil:if [ "$x" -ge 2 ]; then …
-
Testează dacă valoarea lui
x
(care se presupune că este numerică) este cel puțin 2, în bash / ksh / zsh:if ((x >= 2)); then …
Comentarii
- Rețineți că un singur parantez acceptă
-a
în loc de&&
, deci se poate scrie:[ -L $file -a -f $file ]
, care reprezintă același număr de caractere din paranteze fără[
și]
… - @AlexisWilke Operatorii
-a
și-o
sunt problematice deoarece pot duce la analize incorecte dacă unii dintre operanzii implicați par a fi operatori. ‘ de ce nu le menționez ‘: au un avantaj zero și nu au ‘ nu funcționează întotdeauna. Și nu scrieți niciodată expansiuni variabile necotate fără un motiv întemeiat:[[ -L $file -a -f $file ]]
este bine, dar cu paranteze simple aveți nevoie de[ -L "$file" -a -f "$file" ]
(ceea ce este ok, de exemplu, dacă$file
începe întotdeauna cu/
sau./
). - Rețineți că it ‘ s
[[ -L $file && -f $file ]]
(nu-a
cu[[...]]
variantă).
Răspuns
[
vs [[
Acest răspuns va acoperi [
vs [[
subset al întrebării.
Unele diferențe în Bash 4.3.11:
-
POSIX vs Bash extension:
-
[
este POSIX -
[[
este o extensie Bash inspirată de f rom Korn shell
-
-
comanda regulată vs magie
-
[
este doar o comandă obișnuită cu un nume ciudat.]
este doar ultimul argument al[
.
Ubuntu 16.04 are de fapt un executabil pentru acesta la
/usr/bin/[
furnizat de coreutils , dar versiunea integrată bash are prioritate.Nimic nu este modificat în modul în care Bash analizează comanda.
În special,
<
este redirecționare,&&
și||
concatenează mai multe comenzi,( )
generează sub-shell, cu excepția cazului în care a scăpat de\
, iar extinderea cuvântului are loc ca de obicei.-
[[ X ]]
o singură construcție care face caX
să fie analizat magic.<
,&&
,||
și()
sunt tratate special, iar regulile de împărțire a cuvintelor sunt diferite.Există și alte diferențe, cum ar fi
=
și=~
.
În basheză:
[
este o comandă încorporată și[[
este un cuvânt cheie: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword -
-
<
-
[[ a < b ]]
: comparație lexicografică -
[ a \< b ]
: La fel ca mai sus.\
este necesar sau face redirecționare ca pentru orice altă comandă. Extensie Bash. -
expr x"$x" \< x"$y" > /dev/null
sau[ "$(expr x"$x" \< x"$y")" = 1 ]
: echivalente POSIX, vezi: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989
-
-
&&
și||
-
[[ a = a && b = b ]]
: adevărat, logic și -
[ a = a && b = b ]
: eroare de sintaxă,&&
analizat ca separator de comenzi ȘIcmd1 && cmd2
-
[ a = a ] && [ b = b ]
: POSIX echivalent de încredere -
[ a = a -a b = b ]
: aproape echivalent, dar depreciat de POSIX deoarece este nebun și nu reușește pentru unele valoria
saub
cum ar fi!
sau(
care ar fi interpretat ca operații logice
-
-
(
-
[[ (a = a || a = b) && a = b ]]
: fals. Fără( )
, ar fi adevărat deoarece[[ && ]]
are o prioritate mai mare decât[[ || ]]
-
[ ( a = a ) ]
: eroare de sintaxă,()
este interpretată ca un subshell -
[ \( a = a -o a = b \) -a a = b ]
: echivalent, dar()
,-a
și-o
sunt depreciate de POSIX. Fără\( \)
ar fi adevărat deoarece-a
are o prioritate mai mare decât-o
-
{ [ a = a ] || [ a = b ]; } && [ a = b ]
echivalent POSIX neacceptat. Cu toate acestea, în acest caz, am fi putut scrie doar:[ a = a ] || [ a = b ] && [ a = b ]
deoarece||
și&&
operatorii shell au prioritate egală spre deosebire de[[ || ]]
și[[ && ]]
și-o
,-a
și[
-
-
divizarea cuvintelor și generarea numelui de fișier la expansiuni (split + glob )
-
x="a b"; [[ $x = "a b" ]]
: adevărat, ghilimelele nu sunt necesare -
x="a b"; [ $x = "a b" ]
: sintaxă eroare, se extinde la[ a b = "a b" ]
-
x="*"; [ $x = "a b" ]
: eroare de sintaxă dacă există mai multe fișiere în directorul curent . -
x="a b"; [ "$x" = "a b" ]
: echivalent POSIX
-
-
=
-
[[ ab = a? ]]
: adevărat, deoarece face potrivirea modelului (* ? [
sunt magice). Nu se extinde la f se află în directorul curent. -
[ ab = a? ]
:a?
glob se extinde. Deci, poate fi adevărat sau fals în funcție de fișierele din directorul curent. -
[ ab = a\? ]
: fals, nu expansiune glob -
=
și==
sunt aceleași în ambele[
și[[
, dar==
este o extensie Bash. -
case ab in (a?) echo match; esac
: echivalent POSIX -
[[ ab =~ "ab?" ]]
: fals, pierde magia cu""
în Bash 3.2 și versiunile ulterioare și compatibilitatea cu bash 3.1 nu este activată (cum ar fi cuBASH_COMPAT=3.1
) -
[[ ab? =~ "ab?" ]]
: adevărat
-
-
=~
-
[[ ab =~ ab? ]]
: adevărat, POSIX extins expresie regulată se potrivește,?
nu se extinde glob -
[ a =~ a ]
: eroare de sintaxă. Fără echivalent bash. -
printf "ab\n" | grep -Eq "ab?"
: echivalent POSIX (numai date cu o singură linie) -
awk "BEGIN{exit !(ARGV[1] ~ ARGV[2])}" ab "ab?"
: Echivalent POSIX.
-
Recomandare: folosiți întotdeauna []
Există echivalente POSIX pentru fiecare [[ ]]
construct pe care l-am văzut.
Dacă utilizați [[ ]]
, veți:
- pierdeți portabilitatea
- forțați cititorul să învețe complexitățile unei alte extensii bash.
[
este doar o comandă obișnuită cu un nume ciudat, nu este implicată nicio semantică specială.
Mulțumită Stéphane Chazelas pentru corecții și completări importante.
Comentarii
- @St é phaneChazelas mulțumesc pentru informații! Am ‘ am adăugat
expr
la răspuns. Termenul ” Bash ex tensiunea ” nu înseamnă că Bash a fost primul shell care a adăugat o sintaxă, învățarea POSIX sh vs Bash este deja suficientă pentru a mă înnebuni. - Vedeți
man test
dacă ați încercatman [
și v-ați pierdut. Aceasta va explica varianta POSIX. - Corecție:
]
este un argument pentru comanda[
, dar nu ‘ t împiedică folosirea altor argumente.]
trebuie să fie ultimul argument pentru[
, dar poate apărea și ca parte a expresiei de testare. De exemplu,if [ "$foo" = ] ]; then
va testa dacă variabilafoo
este setată la „] ” (la fel caif [ ] = "$foo" ]; then
). - @GordonDavisson mulțumesc, nu ‘ nu știu asta, fix.
- @ tgm1024 – Monicawasm a tratat da, acesta este, de asemenea, o considerație valabilă.
Răspuns
Din documentație bash :
(list)
lista este executată într-un mediu sub-shell (consultați MEDIUL DE EXECUTARE A COMANDEI mai jos). Atribuțiile variabile și comenzile integrate care afectează mediul shell nu rămân în vigoare după finalizarea comenzii. Starea de returnare este starea de ieșire a listei.
Cu alte cuvinte, vă asigurați că orice se întâmplă în „listă” (cum ar fi un cd
) nu are niciun efect în afara (
și )
. Singurul lucru care se va scurge este codul de ieșire al ultimei comenzi sau cu set -e
prima comandă care generează o eroare (altele decât câteva, cum ar fi if
, while
etc.)
((expression))
Expresia este evaluată în conformitate cu regulile descrise mai jos în EVALUAREA ARITMETICĂ. Dacă valoarea expresiei este diferită de zero, starea de returnare este 0; în caz contrar, starea de returnare este 1. Acest lucru este exact echivalent cu ” expresie „.
Aceasta este o extensie bash care vă permite să faceți matematică. Acest lucru este oarecum similar cu utilizarea expr
fără toate limitările expr
(cum ar fi spații peste tot, evadarea *
etc.)
[[ expression ]]
Returnează o stare de 0 sau 1 în funcție de evaluarea expresiei condiționate a expresiei. Expresiile sunt compuse din elementele primare descrise mai jos în EXPRESII CONDIȚIONALE. Împărțirea cuvintelor și extinderea căii nu se efectuează pe cuvintele dintre [[și]]; se efectuează extinderea tildei, extinderea parametrilor și variabilelor, extinderea aritmetică, substituirea comenzilor, substituirea procesului și eliminarea citatelor. Operatorii condiționați, cum ar fi -f, trebuie să fie necitați pentru a fi recunoscuți ca primari.Când se utilizează cu [[, < și > operatorii sortează lexicografic folosind locația curentă.
Acesta oferă un test avansat pentru a compara șiruri, numere și fișiere un pic ca test
oferă, dar mai puternic.
[ expr ]
Returnează o stare de 0 (adevărat) sau 1 (fals) în funcție de evaluarea expresiei condiționate expr. Fiecare operator și oper și trebuie să fie un argument separat. Expresiile sunt compuse din elementele primare descrise mai sus în EXPRESII CONDIȚIONALE. testul nu acceptă nicio opțiune și nici nu acceptă și ignoră un argument al – ca semn al sfârșitului opțiunilor.[…]
Acesta apelează test
. De fapt, pe vremuri, [
era o legătură simbolică către test
. Funcționează la fel și aveți aceleași limitări. Deoarece un binar știe numele cu care a fost pornit, programul de testare știe când a fost pornit ca [
și își poate ignora ultimul parametru, care este de așteptat să fie ]
. Trucuri Fun Unix.
Rețineți că în cazul bash
, [
și test
sunt funcții încorporate (așa cum se menționează într-un comentariu), totuși se aplică aproape aceleași limitări.
Comentarii
- Deși
test
și[
sunt, desigur, comenzi integrate în Bash, dar este ‘ probabil că un Binarul extern există și el. - Binarul extern pentru
[
nu este o legătură simbolică cătretest
pe majoritatea sistemelor moderne . - Cumva, mi se pare amuzant că se deranjează să creeze două binare separate, care au ambele exact exact ceea ce au nevoie, în loc să le combine doar și să adauge câteva condiționale. Deși de fapt
strings /usr/bin/test
arată că are și textul de ajutor, așa că nu ‘ știu ce să spun. - @ Random832 Îmi dau seama despre raționamentul GNU pentru a evita un comportament neașteptat de arg0, dar despre cerințele POSIX, nu aș fi ‘ aș fi atât de afirmativ. În timp ce comanda
test
este evident necesară pentru a exista ca o comandă bazată pe fișier independentă de standard, nimic din aceasta nu menționează varianta[
să fie implementat și în acest fel. De exemplu, Solaris 11 nu ‘ nu oferă niciun executabil[
, dar este totuși pe deplin conform cu standardele POSIX - (ieșirea 1) are un efect în afara parantezelor.
Răspuns
Câteva exemple:
Test tradițional:
foo="some thing" # check if value of foo is not empty if [ -n "$foo" ] ; then... if test -n "$foo" ; then...
test
și [
sunt comenzi ca oricare altele, deci variabila este împărțită în cuvinte, cu excepția cazului în care este „între ghilimele.
Test în stil nou
[[ ... ]]
este un (mai nou) construcție specială de shell, care funcționează puțin diferit, cel mai evident lucru fiind că nu are variabile divizate de cuvinte:
if [[ -n $foo ]] ; then...
Unele documentație pe [
și [[
aici .
Test aritmetic:
foo=12 bar=3 if (( $foo + $bar == 15 )) ; then ...
„Normal „comenzi:
Toate cele de mai sus acționează ca niște comenzi normale și if
poate lua orice comandă:
# grep returns true if it finds something if grep pattern file ; then ...
Comenzi multiple:
au putem folosi mai multe comenzi. Înfășurarea unui set de comenzi în ( ... )
le rulează în subshell, creând o copie temporară a stării shell-ului (director de lucru, variabile). Dacă avem nevoie pentru a rula temporar un program într-un alt director:
# this will move to $somedir only for the duration of the subshell if ( cd $somedir ; some_test ) ; then ... # while here, the rest of the script will see the new working # directory, even after the test if cd $somedir ; some_test ; then ...
Răspuns
Comenzi de grupare
Bash oferă două moduri de a grupa o listă de comenzi care trebuie executate ca unitate.
( list )
Plasarea unei liste de comenzi între paranteze determină crearea unui mediu subshell și executarea fiecărei comenzi din listă în acel subshell. Deoarece lista este executate într-un subshell, atribuțiile variabile nu rămân în vigoare după finalizarea subshell-ului.
$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a" inside: a=2 outside: a=1
{ list; }
Plasarea unui lista de comenzi între acolade face ca lista să fie executată în contextul curent al shell-ului . Nu este creată nicio sub-coajă. Este necesar următorul punct și virgulă (sau linia nouă). Sursă
${} Parameter expansion Ex: ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s $() Command substitution Ex: result=$(COMMAND) $(()) Arithmetic expansion Ex: var=$(( 20 + 5 ))
Construcții condiționate
Single Bracket ie []
Pentru comparație ==, !=, <,
și >
și trebuie utilizat și pentru comparație numerică eq, ne,lt
și gt
ar trebui utilizat.
Suporturi îmbunătățite ie [[]]
În toate exemplele de mai sus, am folosit doar paranteze simple pentru a încadra expresia condițională, dar bash permite paranteze duble care servește ca o versiune îmbunătățită a sintaxei cu paranteză unică.
Pentru comparație, ==, !=, <,
și >
pot fi utilizate literalmente.
-
[
este un sinonim pentru comanda de testare. Chiar dacă este încorporat în shell creează un proces nou. -
[[
este o nouă versiune îmbunătățită a acestuia, care este un cuvânt cheie, nu un program . -
[[
este înțeles deKorn
șiBash
.