Quelle est la différence entre [[$ a == z *]] et [$ a == z *]?

35

Y at-il une différence entre ces deux.

[[ $a == z* ]]

et

[ $a == z* ] 

Puis-je avoir un exemple où ils auraient des résultats différents?

En outre, en quoi le travail de [[ ]]diffère- [ ]t-il?

munish
la source

Réponses:

41

La différence entre [[ … ]]et [ … ]est principalement couverte par l’ utilisation de single - double brack - bash . De manière cruciale, la [[ … ]]syntaxe spéciale, alors qu’il [s’agit d’un nom amusant pour une commande. [[ … ]]a des règles de syntaxe spéciales pour ce qui est à l'intérieur, [ … ]n'a pas.

Avec la ride supplémentaire d'un caractère générique, voici comment [[ $a == z* ]]est évalué:

  1. Analyser la commande: il s’agit de la [[ … ]]construction conditionnelle autour de l’expression conditionnelle $a == z*.
  2. Analyser l'expression conditionnelle: il s'agit de l' ==opérateur binaire, avec les opérandes $aet z*.
  3. Développez le premier opérande dans la valeur de la variable a.
  4. Évaluez l' ==opérateur: testez si la valeur de la variable acorrespond au modèle z*.
  5. Evaluez l'expression conditionnelle: son résultat est le résultat de l'opérateur conditionnel.
  6. La commande est maintenant évaluée, son statut est 0 si l'expression conditionnelle était vraie et 1 si elle était fausse.

Voici comment [ $a == z* ]est évalué:

  1. Analyser la commande: ceci est la [commande avec les arguments formées en évaluant les mots $a, ==, z*, ].
  2. Développez $ala valeur de la variable a.
  3. Effectuez le fractionnement des mots et la génération du nom de fichier sur les paramètres de la commande.
    • Par exemple, si la valeur de aest la chaîne de 6 caractères foo b*(obtenue par exemple a='foo b*') et que la liste des fichiers du répertoire en cours est (bar , baz, qux, zim, zum), le résultat de l'expansion est la liste suivante des mots: [, foo, bar, baz, ==, zim, zum, ].
  4. Exécutez la commande [avec les paramètres obtenus à l'étape précédente.
    • Avec les exemples de valeurs ci-dessus, la [commande se plaint d'une erreur de syntaxe et renvoie le statut 2.

Note: En venant du développement cité de ne correspond pas ). À l'intérieur , les guillemets doubles ne font pas de différence, sauf à droite des opérateurs de correspondance de chaîne.[[ $a == z* ]] étape 3, la valeur de ane subit pas de fractionnement de mot ni de génération de nom de fichier, car elle se trouve dans un contexte dans lequel un seul mot est attendu (l'argument de gauche de l'opérateur conditionnel ==). Dans la plupart des cas, si un seul mot a du sens à cette position, le développement variable se comporte comme entre guillemets. Il existe toutefois une exception à cette règle: in [[ abc == $a ]], si la valeur de acontient des caractères génériques, elle acorrespond au modèle de caractère générique. Par exemple, si la valeur de ais est a*alors [[ abc == $a ]]vraie (parce que le caractère générique *provenant de l’extension non citée des $acorrespondances *) alors qu’elle [[ abc == "$a" ]]est fausse (parce que le caractère ordinaire*$abc[[ … ]] ( =, ==, !=et =~).

Gilles, arrête de faire le mal
la source
39

[est un alias pour la testcommande. Unix version 6 avait une ifcommande, mais la version 7 (1979) est venue avec le nouveau shell Bourne qui comportait quelques constructions de programmation, y compris la construction if-then-else-elif-fi, et Unix version 7 a ajouté untest commande exécutant la plupart des opérations. "tests" réalisés par la ifcommande dans les versions antérieures.

[est devenu un alias testet les deux ont été intégrés à la coque dans Unix System III (1981) . Il faut toutefois noter que certaines variantes d’Unix n’ont reçu de [commande que bien plus tard ( jusqu’au début des années 2000, sur certains BSD, qui shest basé sur le shell Almquist.test reçu de (une commande intégrée a toujours été incluse dans ashle code source de BSDs il a été initialement désactivé)).

Notez que testaka [est une commande permettant d'effectuer des "tests". Aucune commande n'est effectuée par cette commande. Il n'y a donc aucune raison de dissocier les opérateurs d'affectation et d'égalité. L'opérateur d'égalité est donc =.==n’est supporté que par quelques implémentations récentes de [(et n’est qu’un alias pour =).

Parce [qu’il n’ya rien de plus qu’une commande, elle est analysée de la même manière que toute autre commande du shell.

Dans votre exemple, $adans la mesure où il n’est pas cité, il serait divisé en plusieurs mots conformément aux règles habituelles de fractionnement des mots, et chaque mot subirait une génération de nom de fichier, appelée globbing, pour éventuellement aboutir à plus de mots, chacun de ces mots produisant un argument séparé à la [commande.

De même, z*serait élargi à la liste des noms de fichiers du répertoire actuel commençant par z.

Ainsi , par exemple, si $aest b* = x, et il y a z1, z2, b1et les b2fichiers dans le répertoire courant, la [commande obtiendraient 9 arguments: [, b1, b2, =, x, ==, z1, z2et] .

[analyse ses arguments en tant qu'expression conditionnelle. Ces 9 arguments ne correspondent pas à une expression conditionnelle valide, ce qui devrait donc renvoyer une erreur.

La [[ ... ]]construction a été introduite par la coquille Korn probablement vers 1988, car ksh86aen 1987, elle ne l’avait pas, elle l’ ksh88avait depuis le début.

A côté de ksh (toutes les implémentations), [[...]]est également supporté par bash (depuis la version 2.02) et zsh, mais les trois implémentations sont différentes et il existe des différences entre les versions d’un même shell, bien que les modifications soient généralement compatibles avec les versions antérieures (une exception notable étant la bash =~opérateur connu pour casser quelques scripts après une certaine version lorsque son comportement a changé). [[...]]n'est pas spécifié par POSIX, Unix ou Linux (LSB). Il a été envisagé d’être inclus à quelques reprises, mais n’est pas inclus car sa fonctionnalité commune prise en charge par les principaux shells est déjà couverte par la [commande et la case-in-esacconstruction.

Toute la [[ ... ]]construction constitue une commande. C'est-à-dire qu'il a un statut de sortie (qui est son actif le plus important car il résulte de l'évaluation de l'expression conditionnelle), vous pouvez le diriger vers une autre commande (bien que cela ne soit pas utile), et l'utiliser généralement où vous le souhaitez. utilisez n'importe quelle autre commande (à l'intérieur du shell uniquement, car c'est une construction de shell) mais elle n'est pas analysée comme une commande simple normale. Ce qui est à l'intérieur est analysé par le shell comme une expression conditionnelle et les règles habituelles de fractionnement des mots et de génération de noms de fichiers s'appliquent différemment.

[[ ... ]]est au courant ==depuis le début et équivaut à =1 . Une erreur de ksh est bien (et est source de confusion et de nombreux bugs) est que le =et ==ne sont pas un opérateur d'égalité , mais un opérateur de correspondance de motif (bien que le correspondant aspect peut être désactivé avec les guillemets mais avec des règles peu claires qui diffèrent de la coquille à coquille).

Dans votre code ci [[ $a == z* ]]- dessus , le shell l’analyserait en plusieurs règles similaires aux règles habituelles, le reconnaîtrait comme une comparaison de correspondance de modèle, le traiterait z*comme un modèle à faire correspondre au contenu dua variable.

Généralement, il est plus difficile de se tirer dans le pied [[ ... ]]qu'avec le [commandement. Mais quelques règles comme

  • toujours citer des variables
  • ne jamais utiliser le -aou -oopérateur (utiliser plusieurs [commandes et les &&et || shell opérateurs)

Rendre [fiable avec les coques POSIX.

[[...]]dans différents shells, prennent en charge des opérateurs supplémentaires tels que -nt, les opérateurs de correspondance d'expressions rationnelles ... mais la liste et le comportement varient d'un shell à l'autre et d'une version à l'autre.

Donc, à moins que vous ne sachiez quel shell et quelle version minimum de votre script sera jamais interprété, il est probablement plus sûr de rester avec la [commande standard .


1 Une exception: a [[...]]été ajouté à bash dans la version 2.02. Jusqu'à ce 2.03que cela ait été changé, [[ x = '?' ]]retournerait vrai et [[ x == '?' ]]faux. Ce cite n'a pas empêché correspondance de motif lorsque vous utilisez l' =opérateur dans ces versions, mais a fait lors de l' utilisation ==.

Stéphane Chazelas
la source
Excellente info. Souhaitez-vous s'il vous plaît expliquer pourquoi "ne jamais utiliser l'opérateur -a ou -o"?
grebneke
@grebneke, essayez [ '!' = foo -o a = a ]de bashpar exemple.
Stéphane Chazelas
0

les deux sont utilisés pour évaluer les expressions et [[ne fonctionnera pas avec POSIX, l’ancien shell bourn et [[prend également en charge les modèles de correspondance et les expressions rationnelles. exemple essayez ces

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

harish.venkat
la source
Notez que le shell Bourne n’est pas POSIX et ne [[...]]prend en charge les expressions rationnelles que dans certaines versions de certains shells, tout comme certaines versions de [support prennent en charge la correspondance des expressions rationnelles. Pour la comparaison arithmétique, dans ces coquilles qui supportent [[, vous préférez écrire(( n == 0 && y == 0))
Stéphane Chazelas