Operatori di uguaglianza di Bash (==, -eq)


136

Qualcuno può spiegare la differenza tra -eqe ==negli script bash?

C'è qualche differenza tra i seguenti?

[ $a -eq $b ] e [ $a == $b ]

È semplicemente ==usato solo quando le variabili contengono numeri?

Risposte:


187

È il contrario: =e ==sono per i confronti di stringhe, -eqè per quelli numerici. -eqè nella stessa famiglia -lt, -le, -gt, -ge, e -ne, se questo ti aiuta a ricordare quale è quale.

==è un bash-ism, comunque. È meglio usare POSIX =. In bash i due sono equivalenti, e in sh =è l'unico garantito per funzionare.

$ a=foo
$ [ "$a" = foo ]; echo "$?"       # POSIX sh
0
$ [ "$a" == foo ]; echo "$?"      # bash specific
0
$ [ "$a" -eq foo ]; echo "$?"     # wrong
-bash: [: foo: integer expression expected
2

(Nota a margine: cita quelle espansioni variabili! Non tralasciare le doppie virgolette sopra.)

Se stai scrivendo uno #!/bin/bashscript, ti consiglio di utilizzare [[invece . La forma raddoppiata ha più funzioni, una sintassi più naturale e meno gotcha che ti faranno inciampare. Le virgolette doppie non sono più necessarie in giro $a, per uno:

$ [[ $a == foo ]]; echo "$?"      # bash specific
0

Guarda anche:


1
@DJCrashdummy, [[nel suo insieme è un ksh-ism degli anni '80 che Bash (e molte altre conchiglie) ha adottato. Questo è il punto - se avete [[ a tutti , allora si può tranquillamente supporre che tutte le estensioni KSH implementate intorno ad esso ( fnmatch()pattern matching in stile, ERE espressioni regolari con =~, e sì, la soppressione di corda-scissione e filesystem globbing) saranno a disposizione. Poiché la [[sintassi non è POSIX nella sua interezza, non vi sono ulteriori perdite di portabilità nel presupporre che le funzionalità con cui è nata saranno disponibili.
Charles Duffy,

1
@DJCrashdummy, ... il link che mostrano i punti in modo corretto che le quotazioni sono a volte necessari sul lato destro di [[ $var = $pattern ]], se si vuole quello che sarebbe altrimenti essere interpretato come un modello per fnmatch invece essere interpretato come una stringa letterale. La stringa foonon ha un'interpretazione non letterale, rendendo le citazioni completamente sicure; è solo se l'OP voleva corrispondere, diciamo, foo*(con l'asterisco letterale, non significa nulla che possa venire dopo la stringa foo) che sarebbero necessarie citazioni o escape.
Charles Duffy,

@CharlesDuffy purtroppo non ho idea di cosa ti riferisca, perché il mio commento sembra essere stato eliminato e non ricordo perché è passato parecchio tempo. :-(
DJCrashdummy,

@DJCrashdummy, ... huh, ho pensato che l'avessi ritirato da solo. Fondamentalmente, era un'obiezione riguardo alle espansioni non [[quotate all'interno dell'essere un bashismo (indicando che quella era l'unica ragione per cui non stavi dando alla risposta un +1).
Charles Duffy,

@CharlesDuffy no, non è l'unico motivo: oltre al fatto che non mi piacciono i bash-isms, i ksh-isms ecc. Per compiti semplici (causa solo problemi e confonde i principianti), non capisco perché mescolare single parentesi graffe [ ... ]e doppio segno di uguale ==. : - /
DJCrashdummy

27

Dipende dal costrutto del test attorno all'operatore. Le opzioni disponibili sono doppia parentesi, doppie parentesi graffe, singole parentesi graffe o test

Se usi ((...)) , stai testando l'equità aritmetica con ==come in C:

$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1

(Nota: 0significa truein senso Unix e non zero è un test fallito)

L'uso -eqall'interno della doppia parentesi è un errore di sintassi.

Se si utilizza [...] (o parentesi graffa singola) o [[...]] (o parentesi graffa doppia), oppure testè possibile utilizzare uno di -eq, -ne, -lt, -le, -gt o -ge come confronto aritmetico .

$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0

L' ==interno di parentesi graffe singole o doppie (o testcomando) è uno degli operatori di confronto delle stringhe :

$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1

Come operatore di stringa, =equivale a ==e nota lo spazio bianco intorno =o è ==richiesto.

Mentre puoi farlo [[ 1 == 1 ]]o [[ $(( 1+1 )) == 2 ]]sta testando l'uguaglianza delle stringhe, non l'uguaglianza aritmetica.

Quindi -eqproduce probabilmente il risultato atteso che il valore intero di 1+1sia uguale 2anche se RH è una stringa e ha uno spazio finale:

$ [[ $(( 1+1 )) -eq  "2 " ]]; echo $?
0

Mentre un confronto di stringhe dello stesso raccoglie lo spazio finale e quindi il confronto di stringhe fallisce:

$ [[ $(( 1+1 )) ==  "2 " ]]; echo $?
1

E un confronto di stringhe errato può produrre la risposta sbagliata completa. '10' è lessicograficamente inferiore a '2', quindi viene restituito un confronto di stringhe trueo 0. Così tanti sono morsi da questo errore:

$ [[ 10 < 2 ]]; echo $?
0

vs il test corretto per 10 essendo aritmeticamente inferiore a 2:

$ [[ 10 -lt 2 ]]; echo $?
1

Nei commenti, c'è una domanda sul motivo tecnico che utilizza l'intero -eqsulle stringhe restituisce True per le stringhe che non sono le stesse:

$ [[ "yes" -eq "no" ]]; echo $?
0

Il motivo è che Bash non è tipizzato . Questo -eqfa sì che le stringhe vengano interpretate come numeri interi se possibile inclusa la conversione di base:

$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0

E 0se Bash pensa che sia solo una stringa:

$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1

Quindi [[ "yes" -eq "no" ]]è equivalente a[[ 0 -eq 0 ]]

Ultima nota: molte estensioni specifiche di Bash per i costrutti di test non sono POSIX e pertanto falliranno in altre shell. Altre shell generalmente non supportano [[...]]e ((...))o== .


Sono curioso di sapere il motivo tecnico per [[ "yes" -eq "no" ]]restituire True. In che modo bash obbliga queste stringhe a valori interi che possono essere confrontati? ;-)
odony

4
Le variabili di Bash non sono tipizzate, quindi [[ "yes" -eq "no" ]]è equivalente a [[ "yes" -eq 0 ]] o [[ "yes" -eq "any_noninteger_string" ]]- All True. Il -eqconfronto delle forze intere. Il "yes"è interpretato come un numero intero 0; il confronto è True se l'altro numero intero è uno 0o il risultato della stringa è 0.
dawg,

Boo, hiss re: mostra (non portabile) ==negli esempi di codice e menziona solo (portatile, standardizzato) =sotto.
Charles Duffy,

24

==è un alias specifico per bash =ed esegue un confronto di stringhe (lessicale) anziché un confronto numerico. eqessendo un confronto numerico ovviamente.

Infine, di solito preferisco utilizzare il modulo if [ "$a" == "$b" ]


15
L'utilizzo ==qui non è valido, come =specificato solo da POSIX.
Charles Duffy,

9
Se davvero insisti per usarlo, ==mettilo tra [[e ]]. (E assicurati che la prima riga del tuo script specifichi di usare /bin/bash.)
holgero

18

Ragazzi: diverse risposte mostrano esempi pericolosi. L'esempio di OP ha [ $a == $b ]utilizzato specificamente la sostituzione di variabili non quotate (a partire dalla modifica del 17 ottobre). Per [...]questo è sicuro per l'uguaglianza delle stringhe.

Ma se stai per elencare alternative come [[...]], devi anche informare che il lato destro deve essere citato. Se non citato, è una corrispondenza del modello! (Dalla pagina man di bash: "Qualsiasi parte del pattern può essere quotata per forzare la corrispondenza come stringa.").

Qui in bash, le due affermazioni che producono "yes" sono pattern matching, altre tre sono l'uguaglianza delle stringhe:

$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$

2
Deve essere [ "$lht" = "$rht" ] con le virgolette per essere affidabile anche per l'uguaglianza. Se hai creato un file con touch 'Afoo -o AB', [ $lft = $rht ]tornerà vero, anche se quel nome file non è affatto identico a AB.
Charles Duffy,
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.