Perché `==` si comporta diversamente all'interno di `[…]` in zsh e bash?


9

Ottengo quello che mi aspettavo facendo questo in bash:

[ "a" == "a" ] && echo yes

Mi ha dato yes.

Ma quando lo faccio zsh, ottengo quanto segue:

zsh: = not found

Perché lo stesso comando ( /usr/bin/[) si comporta diversamente in shell diverse?


5
non è lo stesso comando - è un builtin trovato prima che $PATHvenga cercato. e ==non è testsintassi valida per l' /usr/bin/[antenna. Va tutto =bene.
Mikeserv,

Risposte:


18

Non è /usr/bin/[in nessuna delle conchiglie. In Bash, stai usando il comando / incorporatotest[ , e allo stesso modo in zsh .

La differenza è che zsh ha anche =un'espansione : si =fooespande nel percorso foodell'eseguibile. Ciò significa che ==viene trattato come il tentativo di trovare un comando chiamato =nel tuoPATH . Poiché quel comando non esiste, viene visualizzato l'errore

zsh: = not found

che hai visto (e in effetti, questa stessa cosa succederebbe anche se stessi effettivamente usando /usr/bin/[).


È possibile utilizzare ==qui, se si vuole veramente. Funziona come previsto in zsh:

[ "a" "==" "a" ] && echo yes

perché il preventivo impedisce l' =wordesecuzione dell'espansione. È inoltre possibile disabilitare l' equalsopzione con setopt noequals.


Tuttavia, staresti meglio entrambi:

  • Utilizzando single =, il test di uguaglianza compatibile con POSIX ; o
  • Meglio ancora, usando i [[condizionali con== sia in Bash che in zsh . In generale, [[è semplicemente migliore e più sicuro, anche evitando questo tipo di problema (e altri) avendo all'interno regole di analisi speciali.

Qual è la differenza esatta tra [e [[? (Cercare su Google [ vs [[mi dà solo risultati vs, LOL)
Johnson Steward,

2
[[supporta una gamma più ampia di test in entrambi i casi e dispone di regole di analisi personalizzate che evitano la necessità di quotare variabili, operatori e così via. Se stai usando specificamente Bash o zsh, usa [[. Se stai scrivendo uno script portatile, scrivi nel comando [/ compatibile POSIX test(che può essere o meno un comando reale sul tuo sistema in esecuzione).
Michael Homer,

1
Basta usare [[lì e dimenticare [esiste.
Michael Homer,

1
sai ... non sono d'accordo con la tua raccomandazione. [[è diversamente capace. provare questo con esso: for f in *; do [ -e "$f" ] && for a in f d h p S b c; do [ "-$a" "$f" ] && for p in r w x u g; do [ "-$p" "$f" ] || p=-; a=$a$p; done && break; done && printf "%s:\t%s\n" "$a" "$f"; done.
Mikeserv,

3
Beh, =/ ==è probabilmente un caso in cui [[non sia meglio che [, come [[ a == b ]]è fa "a" corrisponde al modello "b" e non è "a" uguale a "b" come ci si aspetterebbe. Ciò significa che è necessario scrivere [[ $a == "$b" ]]per esempio. Almeno, con il [comando, se sai come funziona l'analisi dei comandi, sai che devi scriverlo [ "$a" = "$b" ]per impedire all'operatore split + glob come in altri comandi. Con questo in mente e se non si utilizza -a o -o, [è sicuro nelle implementazioni conformi a POSIX.
Stéphane Chazelas,

2

E zsh e bash danno la stessa risposta ( typeè incorporato anche per entrambe le shell):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

2

[ è un comando incorporato della shell in bash e in zsh:

$ type [
[ is a shell builtin

Dalla documentazione dei comandi integrati Shell :

I comandi integrati sono contenuti nella shell stessa . Quando il nome di un comando incorporato viene utilizzato come prima parola di un comando semplice (vedere Comandi semplici ), la shell esegue direttamente il comando, senza richiamare un altro programma. I comandi integrati sono necessari per implementare funzionalità impossibili o scomode da ottenere con utility separate.

La documentazione ufficiale ( $ help test) consente solo di utilizzare =:

STRING1 = STRING2

Vero se le stringhe sono uguali.

Quindi, l'espressione corretta sarebbe:

$ [ "a" = "a" ] && echo yes
yes

Quello che succede è che bash è un po 'meno severo. Supportare l' ==operatore con [ sembra essere un'estensione bash e non è consigliabile usarlo:

string1 == string2

string1 = string2

Vero se le stringhe sono uguali. Se utilizzato con il comando [[, esegue la corrispondenza del modello come descritto sopra (vedere Costrutti condizionali ).

'=' deve essere usato con il comando test per la conformità POSIX.

Se si desidera utilizzare ==, è necessario utilizzare la [[parola chiave:

$ [[ "a" == "a" ]] && echo yes
yes

Tieni presente che [[è meno portatile (non è POSIX). Ma sia bash che zsh lo supportano.


1

In entrambe le shell bashe zshl' [utilità è integrata nella shell. Questa è l'implementazione di shell di quello strumento, è usata in preferenza al binario /usr/bin/[. I diversi risultati riscontrati sono causati da diverse implementazioni.


In bash, l' [utilità accetta CONDITIONAL EXPRESSIONScome [[comando composto. Secondo la pagina man di bashs entrambi =e ==sono validi:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

In zsh, l' [utilità tenta di implementare POSIX e le sue estensioni dove sono specificate. Nella specifica dell'utilità di test POSIX non è stato ==definito alcun operatore.

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.