Qual è la differenza tra [[$ a == z *]] e [$ a == z *]?


35

C'è qualche differenza tra questi due.

[[ $a == z* ]]

e

[ $a == z* ] 

Posso avere un esempio in cui avrebbero output diversi?

Inoltre, in che cosa [[ ]]differisce il funzionamento di [ ]?

Risposte:


41

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:

  1. Analizza il comando: questo è il [[ … ]]costrutto condizionale attorno all'espressione condizionale $a == z*.
  2. Analizza l'espressione condizionale: questo è l' ==operatore binario, con gli operandi $ae z*.
  3. Espandi il primo operando nel valore della variabile a.
  4. Valuta l' ==operatore: verifica se il valore della variabile acorrisponde al modello z*.
  5. Valuta l'espressione condizionale: il suo risultato è il risultato dell'operatore condizionale.
  6. Il comando viene ora valutato, il suo stato è 0 se l'espressione condizionale era vera e 1 se era falsa.

Ecco come [ $a == z* ]viene valutato:

  1. Analizzare il comando: questo è il [comando con gli argomenti formate valutando le parole $a, ==, z*, ].
  2. Espandi $anel valore della variabile a.
  3. Esegue la divisione delle parole e la generazione del nome file sui parametri del comando.
    • Ad esempio, se il valore 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, ].
  4. Eseguire il comando [con i parametri ottenuti nel passaggio precedente.
    • Con i valori di esempio sopra riportati, il [comando lamenta un errore di sintassi e restituisce lo stato 2.

Nota: nel [[ $a == z* ]]passaggio 3, il valore di anon 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 acontiene caratteri jolly, aviene 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 $acorrispondenze *) mentre [[ abc == "$a" ]]è falso (perché il carattere ordinario*proveniente dall'espansione citata di $anon corrisponde bc). All'interno [[ … ]], le doppie virgolette non fanno la differenza, tranne che sul lato destro degli operatori string matching ( =, ==, !=e =~).


39

[è un alias per il testcomando. La versione 6 di Unix aveva un ifcomando, 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 testcomando che eseguiva la maggior parte dei "test" eseguiti dal ifcomando nelle versioni precedenti.

[è stato creato un alias tested 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 testbuiltin è sempre stato incluso nel ashsorgente, ma su quelli BSD inizialmente era disabilitato)).

Nota che testaka [è 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, $apoiché 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, b1e b2i file nella directory corrente, il [comando otterrebbe 9 argomenti: [, b1, b2, =, x, ==, z1, z2e ].

[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é ksh86anel 1987 non ce l' ksh88aveva 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-esaccostrutto.

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 avariabile.

Generalmente, è più difficile spararsi al piede [[ ... ]]di quanto non lo sia con il [comando. Ma alcune regole simili

  • cita sempre le variabili
  • non usare mai l' operatore -ao -o(usare diversi [comandi e gli operatori &&e || shell )

Fare [affidabile con conchiglie POSIX.

[[...]]in diverse shell supportano operatori extra come -ntregexp 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.03quando 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 ==.


Informazioni fantastiche. Potresti spiegare perché "non usare mai l'operatore -a o -o"?
Grebneke,

@grebneke, provare [ '!' = foo -o a = a ]a bashper esempio.
Stéphane Chazelas

0

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"


Si noti che la shell Bourne non è POSIX, [[...]]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))
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.