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 quand utilisé dans bash (crochets, doubles crochets, parenthèses et doubles parenthèses).

[[ , [ , ( , (( 

Jai vu des gens les utiliser sur des déclarations if comme celle-ci:

if [[condition]] if [condition] if ((condition)) if (condition) 

Commentaires

Réponse

Dans les shells de type Bourne, une instruction if ressemble généralement à

if command-list1 then command-list2 else command-list3 fi 

La clause then est exécutée si le code de sortie du la liste des commandes est égale à zéro. Si le code de sortie est différent de zéro, la clause else est exécutée. command-list1 peut être simple ou complexe. Il peut par exemple sagir dune séquence dun ou plusieurs pipelines séparés par lun des opérateurs ;, &, &&, || ou nouvelle ligne. Les conditions if indiquées ci-dessous ne sont que des cas spéciaux de command-list1:

  1. if [ condition ]

    [ est un autre nom de la commande traditionnelle test. [ / test est un utilitaire POSIX standard. Tous les shells POSIX lont intégré (bien que ce ne soit pas requis par POSIX²). La commande test définit un code de sortie et linstruction if agit en conséquence. Les tests typiques sont de savoir si un fichier existe ou si un nombre est égal à un autre.

  2. if [[ condition ]]

    Ceci est une nouvelle version mise à jour de test ¹ de ksh qui bash , zsh , yash , busybox sh également prendre en charge. Cette construction [[ ... ]] définit également un code de sortie et le if agit en conséquence. Parmi ses fonctionnalités étendues, elle peut tester si une chaîne correspond à un modèle générique (pas dans busybox sh ).

  3. if ((condition))

    Une autre extension ksh que bash et zsh prennent également en charge. Ceci exécute larithmétique. À la suite de larithmétique, un code de sortie est défini et linstruction if agit comme suit rdingly. 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 nest pas POSIX et donc pas portable.

  4. if (command)

    Ceci exécute la commande dans un sous-shell. Lorsque la commande se termine, elle définit un code de sortie et linstruction if agit en conséquence.

    Une raison typique dutiliser 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 de l’environnement du shell. Ces modifications ne sont pas conservées une fois le sous-shell terminé.

  5. if command

    La commande est exécutée et linstruction if agit selon son code de sortie.


¹ mais pas vraiment une commande mais une construction shell spéciale avec sa propre syntaxe distincte de celle de la commande normale, et variant considérablement entre les implémentations de shell

² POSIX nécessite quil y ait un standalone test et [ sur le système cependant, bien que dans le cas de [, plusieurs distributions Linux ont été connues pour être m émettre.

Commentaires

  • Merci davoir inclus la 5ème option. Cette ‘ est la clé pour comprendre comment cela fonctionne réellement et est étonnamment sous-utilisée.
  • Notez que [ est en fait un binaire, pas une commande ou un symbole interne. Vit généralement à /bin.
  • @JulienR. en fait [ est un élément intégré, tout comme test. Il existe des versions binaires disponibles pour des raisons de compatibilité. Découvrez help [ et help test.
  • Il convient de noter que while ((isnt POSIX, $(( cest-à-dire que lexpansion arithmétique est et il est ‘ facile de les confondre. Souvent, une solution de contournement consiste à utiliser quelque chose comme [ $((2+2)) -eq 4 ] utiliser larithmétique dans les déclarations conditionnelles
  • Jaimerais pouvoir voter pour cette réponse plus dune fois. Explication parfaite.

Réponse

  • (…) les parenthèses indiquent un sous-shell . Ce qui est en eux nest pas une expression comme dans de nombreuses autres langues. Cest 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 à lintérieur des parenthèses na aucun effet en dehors des parenthèses. signe dollar, $(…) est une substitution de commande : il y a une commande entre parenthèses et le résultat de la commande est utilisé dans le cadre de la ligne de commande (après des extensions supplémentaires sauf si la substitution est entre guillemets, mais que « s une autre histoire ).
  • { … } les accolades sont comme des parenthèses en ce sens quelles regroupent les commandes, mais elles ninfluencent que lanalyse, pas le regroupement. Le programme x=2; { x=4; }; echo $x imprime 4, tandis que x=2; (x=4); echo $x imprime 2. (De plus, les accolades étant des mots-clés doivent être délimitées et trouvé en position de commande (doù lespace après { et le ; avant }) alors que les parenthèses ne sont pas « t. Cest » juste une bizarrerie de syntaxe.)
    • Avec un signe dollar au début, ${VAR} est un expansion des paramètres , en augmentant la valeur dune variable, avec déventuelles transformations supplémentaires. Le shell ksh93 prend également en charge ${ cmd;} comme forme de substitution de commande qui ne génère pas de sous-shell.
  • ((…)) des doubles parenthèses entourent une instruction arithmétique , cest-à-dire un calcul sur des entiers, avec une syntaxe ressemblant à dautres langages de programmation. Cette syntaxe est principalement utilisée pour les affectations et dans les conditions. Elle nexiste que dans ksh / bash / zsh, pas en sh simple.
    • La même syntaxe est utilisée dans les expressions arithmétiques $((…)), qui sétendent jusquà la valeur entière de lexpression.
  • [ … ] des crochets simples entourent expressions conditionnelles . Les expressions conditionnelles sont principalement construites sur des 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 dun espace autour de chaque opérateur (par exemple [ "$x" = "$y" ], et non [ "$x"="$y" ] ) et un espace ou un caractère comme ; à la fois à lintérieur et à lextérieur des crochets (par exemple [ -n "$foo" ], et non [-n "$foo"] ).
  • [[ … ]] les doubles crochets sont une forme alternative dexpressions conditionnelles dans 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 normal alors que les crochets simples nécessitent [ -L "$file" ] && [ -f "$file" ]. Voir Pourquoi lexpansion des paramètres avec des espaces sans guillemets fonctionne-t-elle entre crochets doubles [[mais pas entre crochets simples [? pour en savoir plus sur ce sujet.
  • Dans le shell, chaque commande est une commande conditionnelle: chaque commande a un statut de retour qui est soit 0 indiquant le succès, soit un entier entre 1 et 255 (et potentiellement plus dans certains shells) indiquant échec. La commande [ … ] (ou la forme de syntaxe [[ … ]]) est une commande particulière qui peut également être orthographiée test … et réussit quand un fichier existe, ou quand une chaîne nest pas vide, ou quand un nombre est plus petit quun autre, etc. La forme de syntaxe ((…)) réussit quand un nombre est différent de zéro .Voici quelques exemples de conditions dans un script shell:

    • Teste si myfile contient la chaîne hello:

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

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

      if [ -e myfile ]; then … 
    • Idem, mais aussi avec des liens symboliques pendantes:

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

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

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

    Commentaires

    • Notez que le crochet unique prend en charge -a au lieu de &&, donc on peut écrire: [ -L $file -a -f $file ], qui est le même nombre de caractères entre crochets sans les [ et ]
    • @AlexisWilke Les opérateurs -a et -o sont problématiques car elles peuvent conduire à des analyses incorrectes si certains des opérandes impliqués ressemblent à des opérateurs. Cest ‘ pourquoi je ne les ‘ pas les mentionner: ils nont aucun avantage et ne ‘ t fonctionnent toujours. Et nécrivez jamais dextensions de variables sans guillemets sans une bonne raison: [[ -L $file -a -f $file ]] cest bien mais avec des crochets simples, vous avez besoin de [ -L "$file" -a -f "$file" ] (ce qui est ok par exemple si $file commence toujours par / ou ./).
    • Notez que il ‘ s [[ -L $file && -f $file ]] (pas de -a avec le [[...]] variante).

    Réponse

    [ vs [[

    Cette réponse couvrira le [ vs [[ sous-ensemble de la question.

    Quelques différences sur Bash 4.3.11:

    • POSIX vs extension Bash:

    • commande régulière contre magie

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

        ] est juste le dernier argument de [.

      Ubuntu 16.04 a en fait un exécutable pour celui-ci à /usr/bin/[ fourni par coreutils , mais la version intégrée de bash a la priorité.

      Rien nest modifié dans la manière dont Bash analyse la commande.

      En particulier, < est une redirection, && et || concaténent plusieurs commandes, ( ) génère sous-shell à moins dêtre échappé par \, et lexpansion des mots se produit comme dhabitude.

      • [[ X ]] est une construction unique qui fait que X soit analysée comme par magie. <, &&, || et () sont traités spécialement et les règles de division des mots sont différentes.

        Il existe également dautres différences telles que = 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 un séparateur de commande AND cmd1 && cmd2
      • [ a = a ] && [ b = b ]: équivalent fiable POSIX
      • [ a = a -a b = b ]: presque équivalent, mais obsolète par POSIX car il est insensé et échoue pour certaines valeurs de a ou b comme ! ou ( qui serait interprété comme des opérations logiques
    • (

      • [[ (a = a || a = b) && a = b ]]: faux. Sans ( ), ce serait vrai car [[ && ]] a une priorité supérieure à [[ || ]]
      • [ ( a = a ) ]: erreur de syntaxe, () est interprété comme un sous-shell
      • [ \( a = a -o a = b \) -a a = b ]: équivalent, mais (), -a et -o sont obsolètes par POSIX. Sans \( \) serait vrai car -a a une priorité supérieure à -o
      • { [ a = a ] || [ a = b ]; } && [ a = b ] équivalent POSIX non obsolète. Dans ce cas particulier cependant, nous aurions pu écrire simplement: [ a = a ] || [ a = b ] && [ a = b ] car les || et && les opérateurs de shell ont la même priorité contrairement à [[ || ]] et [[ && ]] et -o, -a et [
    • division de mot 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" ]: syntaxe erreur, se développe en [ a b = "a b" ]
      • x="*"; [ $x = "a b" ]: erreur de syntaxe sil y a plus dun fichier dans le répertoire courant .
      • x="a b"; [ "$x" = "a b" ]: équivalent POSIX
    • =

      • [[ ab = a? ]]: true, car il fait correspondance de modèle ( * ? [ sont magiques). Ne s’étend pas globalement en f fichiers dans le répertoire courant.
      • [ ab = a? ]: a? glob se développe. Cela peut être vrai ou faux selon les fichiers dans le répertoire courant.
      • [ ab = a\? ]: false, pas glob expansion
      • = et == sont identiques dans [ et [[, mais == est une extension 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?" ]]: true
    • =~

      • [[ ab =~ ab? ]]: true, POSIX étendu expression régulière correspond, ? ne se déplie pas globalement
      • [ a =~ a ]: erreur de syntaxe. Aucun équivalent 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 [[ ]] construction que jai « vue.

    Si vous utilisez [[ ]] vous:

    • perdez la portabilité
    • forcez le lecteur à apprendre les subtilités dune autre extension bash. [ est juste une commande ordinaire avec un nom étrange, aucune sémantique spéciale nest impliquée.

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

    Commentaires

    • @St é phaneChazelas merci pour linfo! Jai ‘ jai ajouté expr à la réponse. Le terme  » Bash ex tension  » ne veut pas dire que Bash a été le premier shell à ajouter de la syntaxe, apprendre POSIX sh vs Bash est déjà suffisant pour me rendre fou.
    • Voir man test si vous avez essayé man [ et que vous vous êtes perdu. Cela expliquera la variante POSIX.
    • Correction: ] est un argument de la commande [, mais ce nest pas le cas ‘ t empêcher lutilisation dautres arguments. ] doit être le dernier argument de [, mais il peut également apparaître dans le cadre de lexpression de test. Par exemple, if [ "$foo" = ] ]; then testera si la variable foo est définie sur « ]  » (tout comme if [ ] = "$foo" ]; then).
    • @GordonDavisson merci, je nai pas ‘ je ne sais pas, corrigé.
    • @ tgm1024 – Monica a maltraité oui, cest aussi une considération valable.

    Réponse

    De la documentation bash :

    La liste (list) est exécutée dans un environnement de sous-shell (voir ENVIRONNEMENT DEXÉCUTION DE COMMANDES ci-dessous). Les affectations de variables et les commandes intégrées qui affectent lenvironnement du shell ne restent pas en vigueur une fois la commande terminée. Létat de retour est létat de sortie de la liste.

    En dautres termes, vous vous assurez que tout ce qui se passe dans « list » (comme un cd) na aucun effet en dehors de ( et ). La seule chose qui fuira 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-uns comme if, while, etc.)

    ((expression)) Lexpression est évaluée selon les règles décrites ci-dessous sous ÉVALUATION ARITHMÉTIQUE. Si la valeur de lexpression est différente de zéro, létat de retour est 0; sinon, létat de retour équivaut exactement à let  » expression « .

    Ceci est une extension bash vous permettant de faire des maths. Cest un peu similaire à lutilisation de expr sans toutes les limitations de expr (comme avoir des espaces partout, échapper à *, etc.)

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

    Lorsquils sont utilisés avec [[, the < et > les opérateurs trient lexicographiquement en utilisant les paramètres régionaux actuels.

    Ceci offre un test avancé pour comparer des chaînes, des nombres et des fichiers un peu comme test offres, mais plus puissantes.

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

    […]

    Celui-ci appelle test. En fait, autrefois, [ était un lien symbolique vers test. Cela fonctionne de la même manière et vous avez les mêmes limitations. Puisquun binaire connaît le nom avec lequel il a été démarré, le programme de test sait quand il a été démarré comme [ et il peut ignorer son dernier paramètre, qui devrait être ]. Astuces Unix amusantes.

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

    Commentaires

    • Bien que test et [ sont bien sûr des commandes intégrées dans Bash, mais il ‘ est probable quun Le binaire externe existe aussi.
    • Le binaire externe pour [ nest pas un lien symbolique vers test sur la plupart des systèmes modernes .
    • Dune manière ou dune autre, je trouve amusant quils prennent la peine de créer deux binaires séparés, qui ont tous les deux exactement ce dont ils ont besoin, au lieu de simplement les combiner et dajouter quelques conditions. Bien quen fait strings /usr/bin/test montre quil a aussi le texte daide, je ne ‘ pas quoi dire.
    • @ Random832 Je comprends votre point de vue sur la justification de GNU pour éviter un comportement arg0 inattendu, mais sur les exigences POSIX, je ne ‘ pas être aussi affirmatif. Alors que la commande test est évidemment requise pour exister en tant que commande basée sur un fichier autonome par la norme, rien dans elle nindique que sa variante [ doit être mis en œuvre de cette façon aussi. Par exemple, Solaris 11 ne fournit ‘ aucun exécutable [ mais est néanmoins entièrement conforme aux normes POSIX
    • (exit 1) a un effet en dehors des parenthèses.

    Answer

    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.

    Nouveau test de style

    [[ ... ]] est un (plus récent) construction spéciale du shell, qui fonctionne un peu différemment, la chose la plus évidente étant quelle ne divise pas les mots par des variables:

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

    Certains documentation sur [ et [[ ici .

    Test arithmétique:

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

    « Normal « commandes:

    Toutes les commandes ci-dessus agissent comme des commandes normales, et if peut prendre nimporte quelle commande:

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

    Commandes multiples:

    Ou nous pouvons utiliser plusieurs commandes. Emballer un ensemble de commandes dans ( ... ) les exécute dans un sous-shell, créant une copie temporaire de l’état du shell (répertoire de travail, variables). Si nous avons besoin pour exécuter un programme temporairement 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 ... 

    Réponse

    Commandes de regroupement

    Bash fournit deux façons de regrouper une liste de commandes à exécuter comme une unité.

    ( list ) Le fait de placer une liste de commandes entre parenthèses entraîne la création dun environnement de sous-shell et lexécution de chacune des commandes de la liste dans ce sous-shell. Puisque la liste est exécutées 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; } Placement dun la liste des commandes entre accolades entraîne lexécution de la liste dans le contexte actuel du shell . Aucun sous-shell nest créé. Le point-virgule (ou nouvelle ligne) suivant la liste est obligatoire. 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 ie []
    À titre de comparaison ==, !=, <, et > et doivent être utilisés et pour la comparaison numérique eq, ne,lt et gt doit être utilisé.

    Supports améliorés ie [[]]

    Dans tous les exemples ci-dessus, nous navons utilisé que des crochets simples pour encadrer lexpression conditionnelle, mais bash autorise les doubles crochets qui servent de version améliorée de la syntaxe à crochet simple.

    À titre de comparaison, ==, !=, <, et > peuvent utiliser littéralement.

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

    Source

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *