Un collègue a récemment déclaré dans une revue de code que la [[ ]]
construction devait être préférée [ ]
à des constructions comme
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
Il n'a pas pu fournir de justification. Est-ce qu'il y a un?
bash
if-statement
syntax
Leonard
la source
la source
[[
à lui, le code est bon et clair, mais rappelez-vous ce jour où vous porterez vos scripts sur le système avec le shell par défaut qui n'est pasbash
ouksh
, etc.[
est plus laid, encombrant, mais fonctionne commeAK-47
dans n'importe quelle situation.Réponses:
[[
a moins de surprises et est généralement plus sûr à utiliser. Mais ce n'est pas portable - POSIX ne spécifie pas ce qu'il fait et seuls certains shells le supportent (à part bash, j'ai entendu que ksh le supportait aussi). Par exemple, vous pouvez fairepour tester si un fichier existe. Mais avec
[
, vous devez citer$b
, car il divise l'argument et développe des choses comme"a*"
(où le[[
prend littéralement). Cela a aussi à voir avec la façon dont[
peut être un programme externe et reçoit son argument normalement comme tous les autres programmes (bien qu'il puisse également être un programme intégré, mais il n'a toujours pas cette gestion spéciale).[[
a également d'autres fonctionnalités intéressantes, comme la correspondance d'expressions régulières=~
avec des opérateurs comme ils sont connus dans les langages de type C. Voici une bonne page à ce sujet: Quelle est la différence entre test[
et[[
? et tests basiquesla source
[[ ]]
mais l'interprète comme signifiant la même chose que[ ]
.#!/bin/sh
puis je les change pour les utiliser#!/bin/bash
dès que je me fie à une fonctionnalité spécifique de BASH, pour indiquer que ce n'est plus le shell Bourne portable.Différences de comportement
Quelques différences sur Bash 4.3.11:
Extension POSIX vs Bash:
[
est POSIX[[
est une extension Bash ¹commande régulière vs magie
[
est juste une commande régulière avec un nom étrange.]
n'est qu'un argument[
qui empêche l'utilisation d'autres arguments.Ubuntu 16.04 a en fait un exécutable
/usr/bin/[
fourni par coreutils , mais la version bash intégrée a priorité.Rien n'est modifié dans la façon dont Bash analyse la commande.
En particulier, la
<
redirection&&
et la||
concaténation de plusieurs commandes( )
génèrent des sous-coquilles à moins qu'elles ne soient échappées\
et l'expansion des mots se produit comme d'habitude.[[ X ]]
est une construction unique qui faitX
être analysée comme par magie.<
,&&
,||
Et()
sont traités spécialement, et les règles de séparation de mots sont différents.Il existe également d'autres différences comme
=
et=~
.En Bashese:
[
est une commande intégrée, et[[
est un mot clé: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword<
[[ a < b ]]
: comparaison lexicographique[ a \< b ]
: Comme ci-dessus.\
requis ou bien fait une redirection comme pour toute autre commande. Extension Bash.expr a \< b > /dev/null
: Équivalent POSIX², voir: Comment tester des chaînes lexicographiques inférieures ou égales dans Bash?&&
et||
[[ a = a && b = b ]]
: vrai, logique et[ a = a && b = b ]
: erreur de syntaxe,&&
analysée comme séparateur de commandes ANDcmd1 && cmd2
[ a = a -a b = b ]
: équivalent, mais déconseillé par POSIX³[ a = a ] && [ b = b ]
: POSIX et équivalent fiable(
[[ (a = a || a = b) && a = b ]]
: faux[ ( a = a ) ]
: erreur de syntaxe,()
est interprétée comme un sous-shell[ \( a = a -o a = b \) -a a = b ]
: équivalent, mais()
est déconseillé par POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
Équivalent POSIX⁵fractionnement de mots et génération de nom de fichier lors des expansions (split + glob)
x='a b'; [[ $x = 'a b' ]]
: vrai, les guillemets ne sont pas nécessairesx='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 courant.x='a b'; [ "$x" = 'a b' ]
: Équivalent POSIX=
[[ ab = a? ]]
: vrai, car il fait correspondre les motifs (* ? [
sont magiques). N'étend pas les fichiers glob dans le répertoire en cours.[ ab = a? ]
:a?
glob se développe. Cela peut donc être vrai ou faux selon les fichiers du répertoire courant.[ ab = a\? ]
: expansion fausse, pas globale=
et==
sont les mêmes dans les deux[
et[[
, mais==
c'est une extension Bash.case ab in (a?) echo match; esac
: Équivalent POSIX[[ ab =~ 'ab?' ]]
: false⁴, perd de la magie avec''
[[ ab? =~ 'ab?' ]]
: vrai=~
[[ ab =~ ab? ]]
: true, correspondance d' expression régulière étendue POSIX ,?
ne se développe pas globalement[ a =~ a ]
: erreur de syntaxe. Pas d'équivalent bash.printf 'ab\n' | grep -Eq 'ab?'
: Équivalent POSIX (données sur une seule ligne)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Équivalent POSIX.Recommandation : toujours utiliser
[]
.Il existe des équivalents POSIX pour chaque
[[ ]]
construction que j'ai vue.Si vous vous utilisez
[[ ]]
:[
est juste une commande régulière avec un nom étrange, aucune sémantique spéciale n'est impliquée.¹ Inspiré de la
[[...]]
construction équivalente de la coque Korn² mais échoue pour certaines valeurs de
a
oub
(comme+
ouindex
) et effectue une comparaison numérique sia
etb
ressemble à des nombres décimaux.expr "x$a" '<' "x$b"
fonctionne autour des deux.³ et échoue également pour certaines valeurs de
a
oub
comme!
ou(
.⁴ dans bash 3.2 et supérieur et la compatibilité fournie avec bash 3.1 n'est pas activée (comme avec
BASH_COMPAT=3.1
)⁵ bien que le regroupement (ici avec le
{...;}
groupe de commandes au lieu(...)
duquel exécuterait un sous-shell inutile) n'est pas nécessaire car les opérateurs shell||
et&&
(par opposition aux opérateurs||
et&&
[[...]]
ou aux opérateurs-o
/-a
[
) ont la même priorité. Ce[ a = a ] || [ a = b ] && [ a = b ]
serait donc équivalent.la source
[
pour les mêmes raisons.[[ ]]
a plus de fonctionnalités - je vous suggère de jeter un œil au Guide de script avancé Bash pour plus d'informations, en particulier la section de commande de test étendue du chapitre 7. Tests .Par ailleurs, comme le note le guide, a
[[ ]]
été introduit dans ksh88 (la version 1988 du shell Korn).la source
De quel comparateur, test, support ou double support est le plus rapide? ( http://bashcurescancer.com )
la source
[[
pourrait apporter. Mais alors, je suis un vieux pet old school :-)[
ettest
même si des versions externes existent également.PS1=...crazy stuff...
et / ou$PROMPT_COMMAND
); pour ceux-ci, je ne veux pas de retard perceptible dans l'exécution du script.apt-get update
si cela fait plus de X heures depuis sa dernière exécution. C'est un grand soulagement quand on peut laisser la portabilité hors de la liste déjà trop longue des contraintes pour le code.Si vous aimez suivre le guide de style de Google :
Test,
[
et[[
la source
[[ -d ~ ]]
renvoie vrai (ce qui implique qu'il a~
été étendu à/home/user
). Je pense que Google aurait dû être plus précis dans son écriture.Une situation typique où vous ne pouvez pas utiliser
[[
est dans un script configure.ac des outils automatiques, les crochets ont une signification spéciale et différente, vous devrez donc utiliser à latest
place de[
ou[[
- Notez ce test et[
sont le même programme.la source
[
à être défini comme une fonction shell POSIX?[[]] les crochets doubles ne sont pas pris en charge sous certaines versions de SunOS et totalement non pris en charge à l'intérieur des déclarations de fonctions par: GNU bash, version 2.02.0 (1) -release (sparc-sun-solaris2.6)
la source
En résumé, [[est préférable car il ne crée pas d'autre processus. Aucune parenthèse ou une parenthèse simple n'est plus lente qu'une parenthèse double parce qu'elle accélère un autre processus.
la source
type [
pour voir cela.[[
, à la différence de[
, la syntaxe est interprétée par l'interpréteur de ligne de commande bash. En bash, essayez de tapertype [[
. unix4linux a raison: bien que les[
tests Bourne-shell classiques engendrent un nouveau processus pour déterminer la valeur de vérité, la[[
syntaxe (empruntée à ksh par bash, zsh, etc.) ne le fait pas.[
est intégré à Bash ainsi qu'à Dash (le/bin/sh
dans toutes les distributions Linux dérivées de Debian).