web-dev-qa-db-fra.com

Pourquoi `[` a coquille intégré et `[[" mot-clé shell?

Pour autant que je sache, [[ est une version améliorée de [, mais je suis confus quand je vois [[ comme mot clé et [ étant montré comme une intégrée.

[root@server ~]# type [
[ is a Shell builtin
[root@server ~]# type [[
[[ is a Shell keyword

[~ # ~] tldp [~ # ~] dit

Une intégrée peut être un synonyme d'une commande système du même nom, mais Bash les réichier en interne. Par exemple, la commande Bash Echo n'est pas la même que/Bin/Echo, bien que leur comportement soit presque identique.

et

Un mot clé est un mot réservé, un jeton ou un opérateur. Les mots-clés ont une signification particulière pour la coquille et sont en effet les blocs de construction de la syntaxe de la coque. Comme exemples, pour, alors que, faire et! sont des mots-clés. Semblable à une intégrée, un mot clé est codé dur dans Bash, mais contrairement à une intégrée, un mot clé n'est pas en soi une commande, mais une sous-unité d'une construction de commande. [2]

Ne devrait-il pas faire les deux [ et [[ un mot clé? Y a-t-il quelque chose que je manque ici? En outre, ce lien réaffirme que les deux [ et [[ devrait appartenir au même genre.

68
Sree

La différence entre [ et [[ est assez fondamental.

  • [ est une commande. Ses arguments sont traités simplement la manière dont tous les arguments de commandes sont traités. Par exemple, envisagez:

    [ -z $name ]
    

    La coquille va augmenter $name et exécutant les deux fractionnement de mots et génération de nom de fichier sur le résultat, comme pour toute autre commande.

    Par exemple, ce qui suit échouera:

    $ name="here and there"
    $ [ -n $name ] && echo not empty
    bash: [: too many arguments
    

    Pour avoir ce travail correctement, des citations sont nécessaires:

    $ [ -n "$name" ] && echo not empty
    not empty
    
  • [[ est un mot-clé shell et ses arguments sont traités conformément aux règles spéciales. Par exemple, envisagez:

    [[ -z $name ]]
    

    La coquille va augmenter $name Mais, contrairement à toute autre commande, il fonctionnera ni fractionnement de mots ni génération de nom de fichier sur le résultat. Par exemple, les suivants réussiront malgré les espaces intégrés à name:

    $ name="here and there"
    $ [[ -n $name ]] && echo not empty
    not empty
    

Sommaire

[ est une commande et est soumise aux mêmes règles que toutes les autres commandes que la Shell exécute.

Parce que [[ est un mot clé, pas une commande, cependant, la coquille le traite spécialement et qu'elle fonctionne sous des règles très différentes.

84
John1024

Dans v7 Unix - où la coquille de Bourne a fait ses débuts - [ a été appelé test, et il n'existait que comme /bin/test. Donc, le code que vous écririez aujourd'hui comme suit:

if [ "$foo" = "bar" ] ; then ...

vous auriez écrit à la place comme

if test "$foo" = "bar" ; then ...

Cette deuxième notation existe toujours et je trouve qu'il est plus clair sur ce qui se passe: vous appelez une commande appelée test, qui évalue ses arguments et renvoie un Code d'état de sortie que if utilise pour décider quoi faire ensuite. Cette commande peut être intégrée à la coquille ou peut être un programme externe.¹

[ comme alternative à test est venu plus tard .² peut être un synonyme de base de test, mais il est également fourni sous la forme /bin/[ sur les systèmes modernes pour les coquilles qui ne l'ont pas comme intégré.

[ et test peut être mis en œuvre à l'aide du même code. C'est le cas pour /bin/[ et /bin/test sur OS X, où sont-ce qui sont Liens durs sur le même exécutable.³ En conséquence, la mise en œuvre ignore complètement le suivi ]: cela ne nécessite pas si vous l'appelez comme /bin/[, et cela ne se plaint pas si vous do Fournissez-le à /bin/test. ⁴

Aucune de ces histoires n'affecte [[, car il n'y avait jamais eu de programme primordial appelé [[. Il existe uniquement à l'intérieur de ces coquilles qui l'implouent comme une extension à la POSIX Shell .

Une partie de la distinction entre "intégrée" et "mot-clé" est due à cette histoire. Cela reflète également le fait que les règles de la syntaxe pour l'analyse [[ expressions est différente, comme indiqué dans Réponse de John1024 . ⁵


Notes de bas de page:

  1. Lorsque vous le regardez de cette façon, cela indique clairement pourquoi vous devez mettre des espaces autour de [ Dans les scripts Shell, contrairement à la manière dont les parenthèses et les crochets travaillent dans la plupart des autres langages de programmation. Si l'analyseur de commande de la coquille a permis if["$x"..., il devrait également autoriser iftest"$x"...

  2. C'est arrivé vers 1980. /bin/[ n'existe pas dans ma copie de Ancien Unix v7 de 1979, ni man test Documentez-le comme un alias. Dans l'entrée de page Man correspondante, j'ai dans une copie de pré-version du manuel System III Manuel de 1980, IT est Répertorié.

  3. ls -i /bin/[ /bin/test

  4. Mais ne comptez pas sur ce comportement. La version intégrée Bash de [ nécessite la fermeture ] et son intégré test _ La mise en œuvre se plaindre si vous do Fournissez-la.

  5. La distinction de commande externe intégrée peut également importer une autre raison: les deux implémentations peuvent se comporter différemment. C'est le cas pour echo sur de nombreux systèmes. Parce qu'il n'y a qu'une seule implémentation, aucune distinction de ce type n'est nécessaire pour un mot clé.

63
Warren Young

[ était à l'origine juste une commande externe, un autre nom pour /bin/test. Mais quelques commandes, telles que [ et echo, sont utilisées si fréquemment dans des scripts shell que les implémentations de shell ont décidé de copier le code directement dans la coque elle-même, plutôt que de gérer un autre processus à chaque fois qu'ils sont utilisé. Cela a transformé ces commandes en "cométine", bien que vous puissiez toujours appeler le programme externe via son chemin complet.

[[ est venu beaucoup plus tard. Bien que la construction soit mise en œuvre interne dans la coquille, elle est analysée comme des commandes externes. Comme expliqué dans la réponse de John1024, cela signifie que les variables non cotées obtiendront la fractionnement de mots sur eux, et les jetons comme > et < sont traités comme une redirection d'E/S. Cela a fait de l'écriture d'expressions de comparaison complexes incommence. [[ a été créé sous forme de syntaxe Shell, de sorte qu'il puisse être analysé de manière idéologique. Dans [[ variables ne reçoivent pas la scission de Word, < et > peuvent être utilisés comme opérateurs de comparaison, = peut se comporter différemment selon que le paramètre suivant est cité ou non, etc. Il s'agit de toutes les commodités qui rendent [[ plus facile à utiliser que les [ Commande/intégrée.

Ils ne pouvaient pas simplement recouvrir [ en tant que syntaxe comme celle-ci car elle aurait été un changement incompatible avec des millions de scripts. En utilisant la nouvelle syntaxe [[, qui n'existait pas auparavant, ils pourraient totalement réorganiser la manière dont elle est utilisée de manière compatible à la hausse.

Ceci est similaire à l'évolution qui a entraîné une syntaxe $((...)) Syntaxe pour les expressions arithmétiques, qui a principalement remplacé la commande traditionnelle expr.

3
Barmar

Le plus récent [[ in bash est une optimisation de [.

Le classique [ a un grand inconvénient, lorsqu'il est utilisé fréquemment pour effectuer une opération triviale: elle va frayer un nouveau processus à chaque fois:
[.____] (Cela crée un nouvel espace d'adressage juste pour comparer 0 et 1! À chaque fois!)

Je pense qu'un point principal de l'ajout de [[ faisait l'évaluation de l'expression à l'intérieur [ n'accordez pas un processus supplémentaire. Mais comment [ Le travail ne peut pas être changé - cela créerait beaucoup de confusion et de problèmes. Ainsi, l'optimisation a été mise en œuvre avec un nouveau nom de manière plus efficace, à savoir une commande de coquille intégrée.
Il est devenu mot clé de la syntaxe shell comme effet secondaire.

À l'époque [ a été utilisé en premier, c'était la bonne façon de le faire avec un processus externe.

0
Volker Siegel