web-dev-qa-db-fra.com

Quelle est la différence entre les opérateurs Bash [[vs [vs (vs ((?

Je suis un peu confus sur ce que ces opérateurs font différemment lorsqu'ils sont utilisés dans bash (crochets, doubles crochets, parenthèses et double parenthèses).

[[ , [ , ( , ((

J'ai vu des gens les utiliser si des déclarations comme celle-ci:

if [[condition]]

if [condition]

if ((condition))

if (condition)
298
RetroCode

Une instruction if ressemble généralement à

if commands1
then
   commands2
else
   commands3
fi

La clause then est exécutée si le code de sortie de commands1 Est nul. Si le code de sortie est différent de zéro, la clause else est exécutée. commands1 Peut être simple ou complexe. Il peut par exemple s'agir d'une séquence d'un ou plusieurs pipelines séparés par l'un des opérateurs ;, &, && Ou ||. Les conditions if indiquées ci-dessous ne sont que des cas particuliers de commands1:

  1. if [ condition ]

    Il s'agit de la commande Shell test traditionnelle. Il est disponible sur tous les shells POSIX. La commande test définit un code de sortie et l'instruction if agit en conséquence. Les tests typiques consistent à savoir si un fichier existe ou si un nombre est égal à un autre.

  2. if [[ condition ]]

    Il s'agit d'une nouvelle version améliorée de test de ksh que bash et zsh supporte également. Cette commande test définit également un code de sortie et l'instruction if agit en conséquence. Parmi ses fonctionnalités étendues, il peut tester si une chaîne correspond à une expression régulière.

  3. if ((condition))

    Une autre extension ksh que bash et zsh prend également en charge. Ceci exécute l'arithmétique. À la suite de l'arithmétique, un code de sortie est défini et l'instruction if agit en conséquence. Il renvoie un code de sortie de zéro (vrai) si le résultat du calcul arithmétique est différent de zéro. Comme [[...]], Ce formulaire n'est pas POSIX et n'est donc pas portable.

  4. if (command)

    Cela exécute la commande dans un sous-shell. Une fois la commande terminée, elle définit un code de sortie et l'instruction if agit en conséquence.

    Une raison typique pour utiliser un sous-shell comme celui-ci est de limiter les effets secondaires de command si command nécessitait des affectations de variables ou d'autres modifications à l'environnement du Shell. Ces modifications ne restent pas après la fin du sous-shell.

  5. if command

    est exécutée et l'instruction if agit en fonction de son code de sortie.

316
John1024
  • Les parenthèses (…) Indiquent un sous-shell . Ce qui s'y trouve n'est pas une expression comme dans beaucoup d'autres langues. C'est une liste de commandes (tout comme les parenthèses extérieures). Ces commandes sont exécutées dans un sous-processus distinct, donc toute redirection, affectation, etc. effectuée à l'intérieur des parenthèses n'a aucun effet en dehors des parenthèses.
    • Avec un signe dollar en tête, $(…) est un substitution de commande : il y a une commande entre parenthèses, et la sortie de la commande est utilisée dans le cadre de la ligne de commande (après extra des extensions à moins que la substitution ne soit entre guillemets, mais c'est ne autre histoire ).
  • Les accolades { … } Sont comme des parenthèses en ce qu'elles regroupent les commandes, mais elles n'influencent que l'analyse, pas le regroupement. Le programme x=2; { x=4; }; echo $x Affiche 4, tandis que x=2; (x=4); echo $x imprime 2. (Les accolades étant les mots clés doivent également être délimités et trouvé en position de commande (d'où l'espace après { et le ; avant }) alors que les parenthèses ne le font pas. C'est juste une bizarrerie de syntaxe.)
    • Avec un signe dollar en tête, ${VAR} Est un expansion de paramètre , se développant à la valeur d'une variable, avec des transformations supplémentaires possibles. Le shell ksh93 Prend également en charge ${ cmd;} Comme forme de substitution de commande qui ne génère pas de sous-shell.
  • ((…)) Des parenthèses doubles entourent un instruction arithmétique , c'est-à-dire un calcul sur des entiers, avec une syntaxe ressemblant à d'autres langages de programmation. Cette syntaxe est principalement utilisée pour les affectations et les conditions. Cela n'existe que dans ksh/bash/zsh, pas dans plain sh.
    • La même syntaxe est utilisée dans les expressions arithmétiques $((…)), qui s'étendent jusqu'à la valeur entière de l'expression.
  • [ … ] Des crochets simples entourent expressions conditionnelles . Les expressions conditionnelles sont principalement basées sur opérateurs tels que -n "$variable" Pour tester si une variable est vide et -e "$file" Pour tester si un fichier existe. Notez que vous avez besoin d'un espace autour de chaque opérateur (par exemple [ "$x" = "$y" ], Pas [ "$x"="$y" ]), et un espace ou un caractère comme ; à l'intérieur et à l'extérieur des crochets (par exemple [ -n "$foo" ], pas [-n "$foo"]).
  • [[ … ]] Les crochets doubles sont une autre forme d'expressions conditionnelles en ksh/bash/zsh avec quelques fonctionnalités supplémentaires, par exemple vous pouvez écrire [[ -L $file && -f $file ]] Pour tester si un fichier est un lien symbolique vers un fichier régulier alors que les crochets simples nécessitent [ -L "$file" ] && [ -f "$file" ]. Voir Pourquoi l'expansion des paramètres avec des espaces sans guillemets fonctionne-t-elle entre crochets doubles [[mais pas entre crochets simples [? pour plus d'informations sur ce sujet.

Dans le shell, chaque commande est une commande conditionnelle: chaque commande a un état de retour qui est soit 0 indiquant le succès, soit un entier compris entre 1 et 255 (et potentiellement plus dans certains obus) indiquant une défaillance. La commande [ … ] (Ou la forme de syntaxe [[ … ]]) Est une commande particulière qui peut également être orthographiée test … Et qui réussit lorsqu'un fichier existe ou lorsqu'une chaîne n'est pas vide, ou lorsqu'un nombre est plus petit qu'un autre, etc. La forme de syntaxe ((…)) réussit lorsqu'un nombre est différent de zéro. Voici quelques exemples de conditions dans un script Shell:

  • Testez si myfile contient la chaîne hello:

    if grep -q hello myfile; then …
    
  • Si mydir est un répertoire, changez-le et faites des choses:

    if cd mydir; then
      echo "Creating mydir/myfile"
      echo 'some content' >myfile
    else
      echo >&2 "Fatal error. This script requires mydir to exist."
    fi
    
  • Testez s'il y a un fichier appelé myfile dans le répertoire courant:

    if [ -e myfile ]; then …
    
  • La même chose, mais incluant également des liens symboliques pendantes:

    if [ -e myfile ] || [ -L myfile ]; then …
    
  • Testez si la valeur de x (qui est supposée être numérique) est au moins 2, de manière portable:

    if [ "$x" -ge 2 ]; then …
    
  • Testez si la valeur de x (qui est supposée être numérique) est au moins 2, en bash/ksh/zsh:

    if ((x >= 2)); then …
    

Depuis la documentation bash :

(list) la liste est exécutée dans un environnement de sous-shell (voir ENVIRONNEMENT D'EXÉCUTION DE COMMANDE ci-dessous). Les affectations de variables et les commandes intégrées qui affectent l'environnement du shell ne restent pas en vigueur une fois la commande terminée. Le statut de retour est le statut de sortie de la liste.

En d'autres termes, vous vous assurez que tout ce qui se passe dans 'list' (comme un cd) n'a aucun effet en dehors du ( et ). La seule chose qui fuit est le code de sortie de la dernière commande ou avec set -e la première commande qui génère une erreur (autre que quelques-unes comme if, while, etc.)

((expression)) L'expression est évaluée selon les règles décrites ci-dessous sous ÉVALUATION ARITHMÉTIQUE. Si la valeur de l'expression est différente de zéro, l'état de retour est 0; sinon le statut de retour est 1. C'est exactement équivalent à laisser "expression".

Il s'agit d'une extension bash vous permettant de faire des calculs. C'est un peu similaire à l'utilisation de expr sans toutes les limitations de expr (comme avoir des espaces partout, échapper *, etc.)

[[ expression ]] Renvoie un état de 0 ou 1 selon l'évaluation de l'expression d'expression conditionnelle. Les expressions sont composées des primaires décrites ci-dessous sous EXPRESSIONS CONDITIONNELLES. Le fractionnement de mots et l'expansion de noms de chemin ne sont pas effectués sur les mots entre [[et]]; l'expansion du tilde, l'expansion des paramètres et des variables, l'expansion arithmétique, la substitution de commande, la substitution de processus et la suppression de devis sont effectuées. Les opérateurs conditionnels tels que -f doivent être entre guillemets pour être reconnus comme primaires.

Lorsqu'ils sont utilisés avec [[ les opérateurs <et> trient lexicographiquement en utilisant les paramètres régionaux actuels.

Cela offre un test avancé pour comparer les chaînes, les nombres et les fichiers un peu comme les offres de test, mais plus puissants.

[ expr ] Retourne un état de 0 (vrai) ou 1 (faux) selon l'évaluation de l'expression conditionnelle expr. Chaque opérateur et oper doit être un argument distinct. Les expressions sont composées des primaires décrites ci-dessus sous EXPRESSIONS CONDITIONNELLES. test n'accepte aucune option, ni n'accepte ni ignore un argument de - comme signifiant la fin des options.

[...]

Celui-ci appelle test. En fait, dans l'ancien temps, [ était un lien symbolique vers test. Cela fonctionne de la même manière et vous avez les mêmes limitations. Puisqu'un binaire connaît le nom avec lequel il a été démarré, le programme de test peut analyser les paramètres jusqu'à ce qu'il trouve un paramètre ]. Trucs amusants Unix.

Notez qu'en cas de bash, [ et test sont des fonctions intégrées (comme mentionné dans un commentaire), mais à peu près les mêmes limitations s'appliquent.

20
Alexis Wilke

[ Vs [[

Cette réponse couvrira le sous-ensemble [ Vs [[ De la question.

Quelques différences sur Bash 4.3.11:

  • Extension POSIX vs Bash:

  • commande régulière vs magie

    • [ Est juste une commande ordinaire avec un nom étrange.

      ] N'est qu'un argument de [ Qui empêche l'utilisation d'autres arguments.

      Ubuntu 16.04 a en fait un exécutable pour cela à /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, < Est une redirection, && Et || Concaténent plusieurs commandes, ( ) Génère des sous-coquilles à moins que \ N'échappe, et l'expansion Word arrive comme d'habitude.

    • [[ X ]] Est une construction unique qui permet d'analyser magiquement X. <, &&, || Et () Sont traités spécialement, et les règles de séparation de mots sont différentes.

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

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

  • <

  • && Et ||

    • [[ a = a && b = b ]]: Vrai, logique et
    • [ a = a && b = b ]: Erreur de syntaxe, && Analysé comme séparateur de commande AND cmd1 && 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é 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 POSIX5
  • Fractionnement de mots et génération de nom de fichier lors des extensions (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 courant.
    • x='a b'; [ "$x" = 'a b' ]: Équivalent POSIX
  • =

    • [[ ab = a? ]]: Vrai, car il le fait correspondance de motifs (* ? [ Est magique). 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\? ]: Faux, pas une expansion globale
    • = Et == Sont les mêmes dans [ Et [[, Mais == Est une extension Bash.
    • case ab in (a?) echo match; esac: équivalent POSIX
    • [[ ab =~ 'ab?' ]]: Faux4, perd de la magie avec ''
    • [[ ab? =~ 'ab?' ]]: Vrai
  • =~

    • [[ ab =~ ab? ]]: Vrai, POSIX expression régulière étendue correspond, ? Ne se développe pas globalement
    • [ a =~ a ]: Erreur de syntaxe. Aucun é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 : utilisez toujours [].

Il y a des équivalents POSIX pour chaque construction [[ ]] Que j'ai vue.

Si vous utilisez [[ ]] Vous:

  • perdre la portabilité
  • forcer le lecteur à apprendre les subtilités d'une autre extension bash. [ 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 dans le Korn Shell

² mais échoue pour certaines valeurs de a ou b (comme + Ou index) et effectue une comparaison numérique si a et b ressemble à des nombres décimaux. expr "x$a" '<' "x$b" Fonctionne autour des deux.

³ et échoue également pour certaines valeurs de a ou b comme ! Ou (.

4 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)

5 bien que le regroupement (ici avec le groupe de commandes {...;} au lieu de (...) qui exécuterait un sous-shell inutile) ne soit pas nécessaire car les opérateurs Shell || et && (contrairement aux opérateurs || et &&[[...]] ou aux opérateurs -o/-a[) ont la même valeur priorité. [ a = a ] || [ a = b ] && [ a = b ] Serait donc équivalent.

Quelques exemples:

Test traditionnel:

foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then... 
if test -n "$foo" ; then... 

test et [ sont des commandes comme les autres, donc la variable est divisée en mots sauf si elle est entre guillemets.

Test de nouveau style

[[ ... ]] est une construction Shell (plus récente) spéciale, qui fonctionne un peu différemment, la chose la plus évidente étant qu'elle ne divise pas les variables Word:

if [[ -n $foo ]] ; then... 

Quelques documentation sur [ et [[ ici .

Test arithmétique:

foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...  

Commandes "normales":

Tous les éléments ci-dessus agissent comme des commandes normales et if peut accepter n'importe quelle commande:

# grep returns true if it finds something
if grep pattern file ; then ...

Commandes multiples:

Ou nous pouvons utiliser plusieurs commandes. Envelopper un ensemble de commandes dans ( ... ) les exécute en sous-shell, créant une copie temporaire de l'état du Shell (répertoire de travail, variables). Si nous devons exécuter temporairement un programme dans un autre répertoire:

# this will move to $somedir only for the duration of the subshell 
if ( cd $somedir ; some_test ) ; then ...

# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...
13
ilkkachu

Commandes de regroupement

Bash propose deux façons de regrouper une liste de commandes à exécuter en tant qu'unité.

( list ) Le placement d'une liste de commandes entre parenthèses provoque la création d'un environnement de sous-shell et l'exécution de chacune des commandes de la liste dans ce sous-shell. Étant donné que la liste est exécutée dans un sous-shell, les affectations de variables ne restent pas en vigueur une fois le sous-shell terminé.

$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a"
inside: a=2
outside: a=1

{ list; } Placer une liste de commandes entre accolades fait que la liste est exécutée dans le contexte Shell actuel . Aucun sous-shell n'est créé. La liste suivante, point-virgule (ou nouvelle ligne) est requise. Source

${} Parameter expansion Ex:  ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s
$() Command substitution Ex: result=$(COMMAND) 
$(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

Constructions conditionnelles

Support simple c'est-à-dire []
En comparaison ==, !=, <, et > et doit être utilisé et pour la comparaison numérique eq, ne,lt et gt doivent être utilisés.

Supports améliorés c'est-à-dire [[]]

Dans tous les exemples ci-dessus, nous n'avons utilisé que des crochets simples pour entourer l'expression conditionnelle, mais bash autorise les crochets doubles qui servent de version améliorée de la syntaxe à crochets simples.

En comparaison ==, !=, <, et > peut utiliser littéralement.

  • [ est un synonyme de commande de test. Même s'il est intégré au Shell, il crée un nouveau processus.
  • [[ en est une nouvelle version améliorée, qui est un mot-clé, pas un programme.
  • [[ est compris par Korn et Bash.

Source

1
Premraj