Pourquoi «==» se comporte-t-il différemment à l'intérieur de «[…]» dans zsh et bash?

9

J'obtiens ce que j'attendais en faisant cela dans bash:

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

Ça m'a donné yes.

Mais quand je le fais zsh, j'obtiens ce qui suit:

zsh: = not found

Pourquoi la même commande ( /usr/bin/[) se comporte-t-elle différemment dans différents shells?

Johnson Steward
la source
5
ce n'est pas la même commande - c'est une fonction intégrée trouvée avant la $PATHrecherche. et ==n'est pas une testsyntaxe valide pour l' /usr/bin/[anway. C'est =bien.
mikeserv

Réponses:

18

Ce n'est /usr/bin/[dans aucun des obus. Dans Bash, vous utilisez la commande / intégréetest[ , et de même dans zsh .

La différence est que zsh a également une =extension : se =foodéveloppe sur le chemin de l' fooexécutable. Cela signifie ==que vous essayez de trouver une commande appelée =dans votrePATH . Puisque cette commande n'existe pas, vous obtenez l'erreur

zsh: = not found

que vous avez vu (et en fait, la même chose se produirait même si vous utilisiez réellement /usr/bin/[).


Vous pouvez utiliser ==ici si vous le voulez vraiment. Cela fonctionne comme prévu dans zsh:

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

car les guillemets empêchent l' =wordexpansion de fonctionner. Vous pouvez également désactiver l' equalsoption avec setopt noequals.


Cependant, vous feriez mieux:

  • En utilisant single =, le test d'égalité compatible POSIX ; ou
  • Mieux encore, en utilisant les [[conditions avec== à la fois dans Bash et zsh . En général, [[c'est juste mieux et plus sûr tout autour, y compris en évitant ce genre de problème (et d'autres) en ayant des règles d'analyse spéciales à l'intérieur.
Michael Homer
la source
Quelle est la différence exacte entre [et [[? (La recherche sur Google pour [ vs [[me donne des résultats pour vsseulement, LOL)
Johnson Steward
2
[[prend en charge une plus large gamme de tests dans les deux cas et dispose de règles d'analyse personnalisées qui évitent d'avoir à citer des variables, des opérateurs, etc. Si vous utilisez spécifiquement Bash ou zsh, utilisez [[. Si vous écrivez un script portable, écrivez dans la commande [/ compatible POSIX test(qui peut ou non être une vraie commande sur votre système en cours d'exécution).
Michael Homer
1
Il suffit de l'utiliser [[et d'oublier qu'il [existe.
Michael Homer
1
vous savez ... je suis en désaccord avec votre recommandation. [[est différemment capable. essayer avec elle: 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
Eh bien, =/ ==est sans doute un cas où [[n'est pas mieux que [, comme [[ a == b ]]est fait « a » correspond au modèle « b » et non est « un » égal à « b » comme on pouvait s'y attendre. Cela signifie que vous devez écrire [[ $a == "$b" ]]par exemple. Au moins, avec la [commande, si vous savez comment fonctionne l'analyse des commandes, vous savez que vous devez l'écrire [ "$a" = "$b" ]pour empêcher l'opérateur split + glob comme dans les autres commandes. Dans cet esprit et si vous n'utilisez pas -a ou -o, [est sûr dans les implémentations conformes POSIX.
Stéphane Chazelas
2

Et zsh et bash donnent la même réponse ( typeest intégré aussi pour les deux shells):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[
Jshura
la source
2

[ est une commande intégrée au shell en bash et en zsh:

$ type [
[ is a shell builtin

Dans la documentation des commandes intégrées de Shell :

Les commandes intégrées sont contenues dans le shell lui-même . Lorsque le nom d'une commande intégrée est utilisé comme premier mot d'une commande simple (voir Commandes simples ), le shell exécute la commande directement, sans appeler un autre programme. Les commandes intégrées sont nécessaires pour implémenter des fonctionnalités impossibles ou peu pratiques à obtenir avec des utilitaires distincts.

La documentation officielle ( $ help test) ne permet d'utiliser que =:

STRING1 = STRING2

Vrai si les chaînes sont égales.

Ainsi, l'expression correcte serait:

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

Ce qui se passe, c'est que bash est un peu moins strict. Soutenir l' ==opérateur avec [ semble être une extension bash et il n'est pas recommandé de l'utiliser:

string1 == string2

chaîne1 = chaîne2

Vrai si les chaînes sont égales. Lorsqu'il est utilisé avec la commande [[, il effectue une correspondance de modèle comme décrit ci-dessus (voir Constructions conditionnelles ).

'=' doit être utilisé avec la commande de test pour la conformité POSIX.

Si vous souhaitez utiliser ==, vous devez utiliser le [[mot - clé:

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

Gardez à l'esprit que [[c'est moins portable (n'est pas POSIX). Mais bash et zsh le supportent.

zuazo
la source
1

Dans les deux shells, bashet zsh, l' [utilitaire est un shell intégré. Il s'agit de l'implémentation des shells de cet outil, il est utilisé de préférence au binaire /usr/bin/[. Les différents résultats que vous rencontrez sont causés par différentes implémentations.


Dans bash, l' [utilitaire accepte CONDITIONAL EXPRESSIONScomme [[commande composée. Selon bashs page de manuel à la fois =et ==sont valables:

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

Dans zsh, l' [utilitaire tente d'implémenter POSIX et ses extensions lorsque ceux-ci sont spécifiés. Dans la spécification de l'utilitaire de test POSIX, aucun ==opérateur n'est défini.

le chaos
la source