549 votes

Quelle est la différence entre les crochets doubles et simples dans bash ?

Je me demandais juste quelle était la différence exacte entre

[[ $STRING != foo ]]

et

[ $STRING != foo ]

est, à part que le dernier est conforme à POSIX, trouvé dans sh et le premier est une extension trouvée dans bash.

4 votes

Au cas où vous vous demanderiez également s'il est possible de ne pas utiliser de parenthèses du tout, par exemple dans le contexte d'un fichier de type if déclaration, voir mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D

0 votes

Également, à partir des docs d'Ubuntu : wiki.ubuntu.com/

1 votes

391voto

Kyle Brandt Points 81077

Il existe plusieurs différences. À mon avis, quelques-unes des plus importantes sont :

  1. [ est un module intégré à Bash et à de nombreux autres shells modernes. Le module intégré [ est similaire à test avec l'exigence supplémentaire d'une clôture ] . Les builtins [ y test imiter la fonctionnalité /bin/[ y /bin/test ainsi que leurs limitations afin que les scripts soient rétrocompatibles. Les exécutables originaux existent toujours, principalement pour la conformité POSIX et la compatibilité ascendante. L'exécution de la commande type [ dans Bash indique que [ est interprété comme un builtin par défaut. (Note : which [ ne recherche que les exécutables sur le PATH et est équivalent à type -P [ . Vous pouvez exécuter type --help pour plus de détails)
  2. [[ n'est pas aussi compatible, il ne fonctionnera pas nécessairement avec ce que l'on appelle le "système". /bin/sh pointe vers. Donc [[ est l'option plus moderne de Bash / Zsh / Ksh.
  3. Parce que [[ est intégré dans le Shell et n'a pas d'exigences en matière d'héritage, vous n'avez pas à vous soucier de la séparation des mots en fonction de l'élément IFS pour se tromper sur les variables qui évaluent une chaîne de caractères avec des espaces. Par conséquent, vous n'avez pas vraiment besoin de mettre la variable entre guillemets.

Pour l'essentiel, le reste n'est qu'une syntaxe plus agréable. Pour voir plus de différences, je recommande ce lien vers une réponse de la FAQ : [Quelle est la différence entre test, [ et [[ ?](http://mywiki.wooledge.org/BashFAQ/031) . En fait, si vous êtes sérieux au sujet des scripts bash, je vous recommande de lire l'intégralité de l'ouvrage wiki y compris la FAQ, Pièges et Guide. La section test de la section guide explique également ces différences et les raisons pour lesquelles les auteurs pensent que [[ est un meilleur choix si vous n'avez pas besoin de vous soucier d'être aussi portable. Les principales raisons sont :

  1. Vous n'avez pas à vous soucier de citer le côté gauche du test pour qu'il soit effectivement lu comme une variable.
  2. Il n'est pas nécessaire d'échapper à la règle "moins que" et "plus que". < > avec des backslashes afin qu'ils ne soient pas évalués comme une redirection d'entrée, ce qui peut vraiment mettre le bazar en écrasant des fichiers. Ceci nous ramène encore une fois à [[ étant un buildin. Si [ (test) est un programme externe, le Shell devrait faire une exception dans la façon dont il évalue < y > seulement si /bin/test est appelé, ce qui n'aurait pas vraiment de sens.

6 votes

Merci, le lien vers la FAQ bash était ce que je cherchais (je ne connaissais pas cette page, merci).

2 votes

J'ai édité votre post avec cette information, mais [ et test sont exécutés en tant que builtins. Les builtins ont été conçus pour remplacer /bin/[ et /bin/test mais devaient également reproduire les limitations des binaires. La commande 'type [' vérifie que le buildin est utilisé. La commande 'which [' recherche uniquement les exécutables dans le PATH et est équivalente à 'type -P ['.

164voto

abhiomkar Points 1643

En bref :

[ est un bash Builtin

[[ ]] sont bash Mots clés

Mots-clés : Les mots-clés sont assez semblables aux builtins, mais la principale différence est que des règles d'analyse spéciales s'appliquent à eux. Par exemple, [ est un buildin bash, alors que [[ est un mot-clé bash. Ils sont tous deux utilisés pour tester des choses, mais comme [[ est un mot-clé plutôt qu'un buildin, il bénéficie de quelques règles d'analyse spéciales qui le rendent beaucoup plus facile :

  $ [ a < b ]
 -bash: b: No such file or directory
  $ [[ a < b ]]

Le premier exemple renvoie une erreur car bash tente de rediriger le fichier b vers la commande [ a ]. Le deuxième exemple fait en fait ce que vous attendez de lui. Le caractère < n'a plus sa signification spéciale d'opérateur de redirection de fichier.

Source : http://mywiki.wooledge.org/BashGuide/CommandsAndArguments

7 votes

[ est une commande POSIX Shell ; elle ne doit pas être intégrée. ] est juste un argument que cette commande recherche, afin que la syntaxe soit équilibrée. La commande est un synonyme de test sauf que test ne cherche pas à conclure ] .

0 votes

111voto

Rafe Points 4602

Différences de comportement

Quelques différences sur Bash 4.3.11 :

  • Extension POSIX vs Bash :

  • commandement régulier contre magie

    • [ est juste une commande normale avec un nom bizarre.

      ] est juste le dernier argument de [ .

    Ubuntu 16.04 dispose d'un exécutable pour ce programme à l'adresse suivante /usr/bin/[ fourni par coreutils mais la version intégrée de bash est prioritaire.

    Rien n'est modifié dans la façon dont Bash analyse la commande.

    En particulier, < est la redirection, && y || concaténer plusieurs commandes, ( ) génère des sous-coquilles, sauf si elles sont échappées par \ et l'expansion des mots se fait comme d'habitude.

    • [[ X ]] est une construction unique qui rend X être analysé comme par magie. < , && , || y () font l'objet d'un traitement spécial, et les règles de division des mots sont différentes.

      Il existe également d'autres différences comme = y =~ .

    En bachique : [ est une commande intégrée, et [[ est un mot-clé : https://askubuntu.com/questions/445749/whats-the-difference-between-Shell-builtin-and-Shell-mot-clé

  • <

  • && y ||

    • [[ a = a && b = b ]] : vrai, logique et
    • [ a = a && b = b ] : erreur de syntaxe, && interprété comme un séparateur de commande AND cmd1 && cmd2
    • [ a = a ] && [ b = b ] : équivalent fiable POSIX
    • [ a = a -a b = b ] : presque équivalent, mais déprécié par POSIX car il est insensé et échoue pour certaines valeurs de a o b comme ! o ( qui seraient interprétés comme des opérations logiques
  • (

    • [[ (a = a || a = b) && a = b ]] : faux. Sans ( ) serait vrai parce que [[ && ]] a une plus grande priorité que [[ || ]]
    • [ ( a = a ) ] : erreur de syntaxe, () est interprétée comme une sous-couche
    • [ \( a = a -o a = b \) -a a = b ] : équivalent, mais () , -a y -o sont dépréciés par POSIX. Sans \( \) serait vrai parce que -a a une plus grande priorité que -o
    • { [ a = a ] || [ a = b ]; } && [ a = b ] équivalent POSIX non déprécié. Dans ce cas particulier cependant, nous aurions pu écrire juste : [ a = a ] || [ a = b ] && [ a = b ] parce que le || y && Shell ont la même préséance contrairement à [[ || ]] y [[ && ]] y -o , -a y [
  • division des mots et génération de noms de fichiers lors des expansions (split+glob)

    • x='a b'; [[ $x = 'a b' ]] : vrai, les guillemets ne sont pas nécessaires
    • x='a b'; [ $x = 'a b' ] : erreur de syntaxe, se développe en [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ] : erreur de syntaxe s'il y a plus d'un fichier dans le répertoire actuel.
    • x='a b'; [ "$x" = 'a b' ] : équivalent POSIX
  • =

    • [[ ab = a? ]] : vrai, parce que c'est le cas filtrage par motif ( * ? [ sont magiques). Ne développe pas les fichiers dans le répertoire courant.
    • [ ab = a? ] : a? glob expanse. Donc peut être vrai ou faux selon les fichiers dans le répertoire courant.
    • [ ab = a\? ] : faux, pas d'expansion globale
    • = y == sont les mêmes dans les deux [ y [[ mais == est une extension de Bash.
    • case ab in (a?) echo match; esac : équivalent POSIX
    • [[ ab =~ 'ab?' ]] : false, perd la magie avec '' dans Bash 3.2 et supérieur et à condition que la compatibilité avec bash 3.1 ne soit pas activée (comme avec BASH_COMPAT=3.1 )
    • [[ ab? =~ 'ab?' ]] : vrai
  • =~

    • [[ ab =~ ab? ]] : true, POSIX expression régulière étendue match, ? n'est pas une extension globale
    • [ a =~ a ] : erreur de syntaxe. Pas d'équivalent en bash.
    • printf 'ab\n' | grep -Eq 'ab?' : équivalent POSIX (données sur une seule ligne uniquement)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?' : équivalent POSIX.

Recommandation : toujours utiliser []

Il existe des équivalents POSIX pour chaque [[ ]] La construction que j'ai vue.

Si vous utilisez [[ ]] vous :

  • perdre la portabilité
  • obliger le lecteur à apprendre les subtilités d'une autre extension de bash. [ est juste une commande normale avec un nom bizarre, aucune sémantique spéciale n'est impliquée.

Merci à Stéphane Chazelas pour les corrections et ajouts importants.

0 votes

Mode d'emploi printf 'ab' | grep -Eq 'ab?' sur if [ … ] ?

1 votes

@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi . [] est une commande tout comme grep . Le site () n'est peut-être pas nécessaire sur cette commande, je n'en suis pas sûr : je l'ai ajouté à cause de la | ça dépend de la façon dont Bash analyse les choses. S'il n'y avait pas de | Je suis sûr que vous pouvez écrire juste if cmd arg arg; then .

1 votes

@meeDamian ouais, pas besoin de () il semble : stackoverflow.com/questions/8965509/

21voto

Premraj Points 345

Support unique c'est-à-dire [] est conforme à POSIX Shell pour enfermer une expression conditionnelle.

Supports doubles c'est-à-dire [[]] est une version améliorée (ou extension) de la version POSIX standard, elle est prise en charge par bash et d'autres shells (zsh, ksh).

En bash, pour une comparaison numérique, on utilise eq , ne , lt y gt avec des doubles crochets pour la comparaison, nous pouvons utiliser == , != , <, y > littéralement.

  • [ est un synonyme de la commande test. Même si elle est intégrée au Shell, elle crée un nouveau processus.
  • [[ est une nouvelle version améliorée de celui-ci, qui est un mot-clé, pas un programme.

par exemple :

[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory 
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works

10voto

Ryan Sampson Points 2898

D'après une lecture rapide des sections pertinentes de la page de manuel, la principale différence semble être que la fonction == y != correspondent à un motif, plutôt qu'à une chaîne littérale, et qu'il existe également l'opérateur =~ opérateur de comparaison regex.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X