Risposte:
La differenza tra [[ … ]]
e [ … ]
è principalmente coperta dall'uso della parentesi singola o doppia - bash . Fondamentalmente, [[ … ]]
è una sintassi speciale, mentre [
è un nome divertente per un comando. [[ … ]]
ha regole di sintassi speciali per ciò che c'è dentro, [ … ]
no.
Con la ruga aggiunta di un carattere jolly, ecco come [[ $a == z* ]]
viene valutata:
[[ … ]]
costrutto condizionale attorno all'espressione condizionale $a == z*
.==
operatore binario, con gli operandi $a
e z*
.a
.==
operatore: verifica se il valore della variabile a
corrisponde al modello z*
.Ecco come [ $a == z* ]
viene valutato:
[
comando con gli argomenti formate valutando le parole $a
, ==
, z*
, ]
.$a
nel valore della variabile a
.a
è la stringa di 6 caratteri foo b*
(ottenuto per esempio a='foo b*'
) e l'elenco dei file nella directory corrente ( bar
, baz
, qux
, zim
, zum
), allora il risultato dell'espansione è il seguente elenco di parole: [
, foo
, bar
, baz
, ==
, zim
, zum
, ]
.[
con i parametri ottenuti nel passaggio precedente.
[
comando lamenta un errore di sintassi e restituisce lo stato 2.Nota: nel [[ $a == z* ]]
passaggio 3, il valore di a
non subisce la suddivisione delle parole e la generazione del nome file, poiché si trova in un contesto in cui è prevista una sola parola (l'argomento di sinistra dell'operatore condizionale ==
). Nella maggior parte dei casi, se una sola parola ha senso in quella posizione, l'espansione variabile si comporta come tra virgolette. Tuttavia, esiste un'eccezione a questa regola: in [[ abc == $a ]]
, se il valore di a
contiene caratteri jolly, a
viene confrontato con il modello di caratteri jolly. Ad esempio, se il valore di a
è a*
allora [[ abc == $a ]]
è vero (perché il carattere jolly *
proveniente dall'espansione non quotata delle $a
corrispondenze *
) mentre [[ abc == "$a" ]]
è falso (perché il carattere ordinario*
proveniente dall'espansione citata di $a
non corrisponde bc
). All'interno [[ … ]]
, le doppie virgolette non fanno la differenza, tranne che sul lato destro degli operatori string matching ( =
, ==
, !=
e =~
).
[
è un alias per il test
comando. La versione 6 di Unix aveva un if
comando, ma la versione 7 (1979) arrivava con la nuova shell Bourne che aveva alcuni costrutti di programmazione incluso il costrutto if-then-else-elif-fi, e la versione 7 di Unix aggiungeva un test
comando che eseguiva la maggior parte dei "test" eseguiti dal if
comando nelle versioni precedenti.
[
è stato creato un alias test
ed entrambi sono stati integrati nella shell in Unix System III (1981) . Tuttavia, va notato che alcune varianti di Unix non hanno avuto un [
comando fino a molto tempo dopo ( fino ai primi anni 2000 su alcuni BSD in cui sh
è basato sulla shell Almquist (un test
builtin è sempre stato incluso nel ash
sorgente, ma su quelli BSD inizialmente era disabilitato)).
Nota che test
aka [
è un comando per fare "test", non c'è assegnazione che quel comando fa, quindi non c'è motivo di non chiarire tra un operatore di assegnazione e di uguaglianza, quindi lo è l'operatore di uguaglianza =
. ==
è supportato solo da alcune recenti implementazioni di [
(ed è solo un alias per =
).
Poiché [
non è altro che un comando, viene analizzato allo stesso modo di qualsiasi altro comando dalla shell.
Nello specifico, nel tuo esempio, $a
poiché non viene citato, verrebbe suddiviso in più parole in base alle normali regole di suddivisione delle parole, e ogni parola verrebbe sottoposta a generazione di nomi di file aka globbing per risultare in probabilmente più parole, ognuna di quelle risultanti in un argomento separato per il [
comando.
Allo stesso modo, z*
sarebbe espanso all'elenco dei nomi di file nella directory corrente a partire da z
.
Così, per esempio, se $a
è b* = x
, e ci sono z1
, z2
, b1
e b2
i file nella directory corrente, il [
comando otterrebbe 9 argomenti: [
, b1
, b2
, =
, x
, ==
, z1
, z2
e ]
.
[
analizza i suoi argomenti come un'espressione condizionale. Questi 9 argomenti non si sommano a un'espressione condizionale valida, quindi probabilmente restituirebbe un errore.
Il [[ ... ]]
costrutto fu introdotto dalla conchiglia Korn probabilmente intorno al 1988 poiché ksh86a
nel 1987 non ce l' ksh88
aveva mentre lo aveva dall'inizio.
Oltre a ksh (tutte le implementazioni), [[...]]
è supportato anche da bash (dalla versione 2.02) e zsh, ma tutte e tre le implementazioni sono diverse e ci sono differenze tra ogni versione di una stessa shell anche se le modifiche sono generalmente compatibili con le versioni precedenti (una notevole eccezione è quella di bash =~
operatore noto per aver interrotto alcuni script dopo una determinata versione quando il suo comportamento è cambiato). [[...]]
non è specificato da POSIX, Unix o Linux (LSB). È stato preso in considerazione per l'inclusione alcune volte, ma non è incluso poiché la funzionalità comune supportata dalle principali shell è già coperta dal [
comando e dal case-in-esac
costrutto.
L'intero [[ ... ]]
costrutto costituisce un comando. Cioè, ha uno stato di uscita (che è la sua risorsa più importante in quanto è il risultato della valutazione dell'espressione condizionale), è possibile reindirizzarlo a un altro comando (anche se non sarebbe utile) e generalmente utilizzarlo ovunque usa qualsiasi altro comando (solo all'interno della shell, poiché è un costrutto di shell) ma non viene analizzato come un normale comando semplice. Ciò che è dentro è analizzato dalla shell come espressione condizionale e le solite regole di suddivisione delle parole e generazione del nome file si applicano in modo diverso.
[[ ... ]]
conosce ==
dall'inizio ed equivale a =
1 . Un errore di ksh (e sta causando confusione e molti bug) è che gli =
e ==
non sono un operatore di uguaglianza ma un operatore di corrispondenza dei modelli (sebbene l' aspetto di corrispondenza possa essere disabilitato con la quotazione ma con regole poco chiare che differiscono da shell a shell).
Nel tuo codice sopra [[ $a == z* ]]
, la shell lo analizzerebbe in diversi token in regole simili ai soliti, riconoscendolo come un confronto di corrispondenza dei modelli, trattandolo z*
come un modello da abbinare al contenuto della a
variabile.
Generalmente, è più difficile spararsi al piede [[ ... ]]
di quanto non lo sia con il [
comando. Ma alcune regole simili
-a
o -o
(usare diversi [
comandi e gli operatori &&
e ||
shell )Fare [
affidabile con conchiglie POSIX.
[[...]]
in diverse shell supportano operatori extra come -nt
regexp corrispondenti agli operatori ... ma l'elenco e il comportamento variano da shell a shell e da versione a versione.
Quindi, a meno che tu non sappia da quale shell e versione minima di esso verrà mai interpretato il tuo script, è probabilmente più sicuro attenersi al [
comando standard .
1 Un'eccezione: è [[...]]
stato aggiunto a bash nella versione 2.02
. Fino a 2.03
quando non è stato modificato, [[ x = '?' ]]
restituisce true mentre [[ x == '?' ]]
restituisce false. Ciò significa che la quotazione non ha impedito la corrispondenza dei modelli quando si utilizza l' =
operatore in quelle versioni, ma lo ha fatto durante l'utilizzo ==
.
[ '!' = foo -o a = a ]
a bash
per esempio.
entrambi sono usati per valutare le espressioni e [[non funzionerà con POSIX bourn shell precedente e [[supporta anche il pattern matching e regex. esempio prova questi
[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"
[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"
[[...]]
supporta regexps solo in alcune versioni di alcune shell, proprio come alcune versioni [
supportano la corrispondenza regexp. Per un confronto aritmico, in quelle conchiglie che supportano [[
, preferiresti scrivere(( n == 0 && y == 0))