Comment utiliser des crochets doubles ou simples, des parenthèses, des accolades

658

Je suis confus par l'utilisation des crochets, des parenthèses, des accolades en Bash, ainsi que par la différence entre leurs formes doubles ou simples. Y a-t-il une explication claire?

Tim
la source

Réponses:

606

Dans Bash, testet [sont intégrés dans le shell.

Le double crochet , qui est un mot-clé shell, permet des fonctionnalités supplémentaires. Par exemple, vous pouvez utiliser &&et ||au lieu de -aet -oet il y a un opérateur de correspondance d'expressions régulières =~.

De plus, dans un test simple, les doubles crochets semblent évaluer beaucoup plus rapidement que les simples.

$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done

real    0m24.548s
user    0m24.337s
sys 0m0.036s
$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done

real    0m33.478s
user    0m33.478s
sys 0m0.000s

Les accolades, en plus de délimiter un nom de variable, sont utilisées pour l' expansion des paramètres afin que vous puissiez faire des choses comme:

  • Tronquer le contenu d'une variable

    $ var="abcde"; echo ${var%d*}
    abc
  • Faire des substitutions similaires à sed

    $ var="abcde"; echo ${var/de/12}
    abc12
  • Utilisez une valeur par défaut

    $ default="hello"; unset var; echo ${var:-$default}
    hello
  • et plusieurs autres

De plus, les extensions d'accolade créent des listes de chaînes qui sont généralement répétées en boucles:

$ echo f{oo,ee,a}d
food feed fad

$ mv error.log{,.OLD}
(error.log is renamed to error.log.OLD because the brace expression
expands to "mv error.log error.log.OLD")

$ for num in {000..2}; do echo "$num"; done
000
001
002

$ echo {00..8..2}
00 02 04 06 08

$ echo {D..T..4}
D H L P T

Notez que les principales fonctionnalités de zéro et d'incrémentation n'étaient pas disponibles avant Bash 4.

Merci à gboffi de m'avoir rappelé les extensions de bretelles.

Les parenthèses doubles sont utilisées pour les opérations arithmétiques :

((a++))

((meaning = 42))

for ((i=0; i<10; i++))

echo $((a + b + (14 * c)))

et ils vous permettent d'omettre les signes dollar sur les variables d'entier et de tableau et d'inclure des espaces autour des opérateurs pour plus de lisibilité.

Des parenthèses simples sont également utilisées pour les indices de tableau :

array[4]="hello"

element=${array[index]}

Des accolades sont requises pour (la plupart / toutes?) Les références de tableau sur le côté droit.

Le commentaire de l'éphémient m'a rappelé que les parenthèses sont également utilisées pour les sous-coquilles. Et qu'ils sont utilisés pour créer des tableaux.

array=(1 2 3)
echo ${array[1]}
2
En pause jusqu'à nouvel ordre.
la source
8
AVERTISSEMENT: Cette fonction est une bombe à fourche, ne l'exécutez pas. Voir: en.wikipedia.org/wiki/Fork_bomb
pause jusqu'à nouvel ordre.
3
Ce n'est qu'une bombe fourchette si vous l'invoquez avec une autre :.
éphémère
7
Aussi pour être complet, je suis juste tombé sur ceci dans un vieux script $[expression]:; il s'agit de l'ancienne syntaxe d'expression arithmétique obsolète pour la nouvelle syntaxe préférée:$((expression))
michael
2
@DennisWilliamson Une autre utilisation des accolades dans la bashcréation de séquences, comme mentionné en périphérie ci-dessous ( stackoverflow.com/a/8552128/2749397 ) Comme je voudrais commenter un peu cette fonctionnalité (comme vous ne l'avez pas mentionnée ;-) Je ' m prendre la liberté d'utiliser la réponse la plus votée comme véhicule ... Deux exemples de littéraux de séquence: echo {01..12}-> 01 02 03 04 05 06 07 08 09 10 11 12(notez le zéro initial); echo {C..Q}-> C D E F G H I J K L M N O P Q. Son utilisation principale est dans les boucles, par exemple, for cnt in {01..12} ; do ... ${cnt} ... ; done
gboffi
1
@gboffi: La fonction de remplissage nul est devenue disponible dans Bash 4. De plus, dans Bash 4, vous pouvez spécifier un incrément dans une séquence: echo {01..12..2}-> "01 03 05 07 09 11". Merci pour le rappel des séquences. Je vais l'ajouter à ma réponse.
pause jusqu'à nouvel ordre.
336
  1. Un seul crochet ( [) appelle généralement un programme nommé [; man testou man [pour plus d'informations. Exemple:

    $ VARIABLE=abcdef
    $ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi
    yes
  2. Le double crochet ( [[) fait la même chose (fondamentalement) qu'un simple crochet, mais est un bash intégré.

    $ VARIABLE=abcdef
    $ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fi
    no
  3. Les parenthèses ( ()) sont utilisées pour créer un sous-shell. Par exemple:

    $ pwd
    /home/user 
    $ (cd /tmp; pwd)
    /tmp
    $ pwd
    /home/user

    Comme vous pouvez le voir, le sous-shell vous a permis d'effectuer des opérations sans affecter l'environnement du shell actuel.

  4. (a) Les accolades ( {}) sont utilisées pour identifier sans ambiguïté les variables. Exemple:

    $ VARIABLE=abcdef
    $ echo Variable: $VARIABLE
    Variable: abcdef
    $ echo Variable: $VARIABLE123456
    Variable:
    $ echo Variable: ${VARIABLE}123456
    Variable: abcdef123456

    (b) Les accolades sont également utilisées pour exécuter une séquence de commandes dans le contexte actuel du shell, par exemple

    $ { date; top -b -n1 | head ; } >logfile 
    # 'date' and 'top' output are concatenated, 
    # could be useful sometimes to hunt for a top loader )
    
    $ { date; make 2>&1; date; } | tee logfile
    # now we can calculate the duration of a build from the logfile

Il existe cependant une subtile différence syntaxique avec ( )(voir la référence bash ); essentiellement, un point - virgule ;après la dernière commande entre accolades est une nécessité, et les accolades {, } doit être entouré par des espaces.

Carl Norum
la source
26
Eh bien, [c'est en fait une fonction intégrée dans Bash, mais elle est censée agir comme /bin/[par opposition à la fonction [[intégrée. [[a des fonctionnalités différentes, comme des opérations plus logiques et différents rôles de citation. De plus: des parenthèses simples sont également utilisées pour les tableaux, la substitution de processus et les globs étendus; des parenthèses doubles sont utilisées pour l'arithmétique; les accolades {}sont utilisées pour le regroupement de commandes ou une multitude de types d'expansion de paramètres ou d'extension d'accolade ou d'extension de séquence. Je suis sûr que j'ai manqué d'autres utilisations aussi ...
éphémère
4
Le double égal dans l'expression if [ $VARIABLE == abcdef ]est un bashisme qui - bien que cela fonctionne - devrait probablement être évité; utilisez explicitement bash ( if [[ ...==...]]) ou indiquez clairement que vous utilisez le conditionnel ( if [ "$VARIABLE" = "abcdef" ]) plus traditionnel . On peut dire que les scripts devraient commencer aussi simples et portables que possible, jusqu'à ce qu'ils aient vraiment besoin de fonctionnalités spécifiques à bash (pour une raison ou une autre). Mais dans tous les cas, l'intention doit être claire; "=" et "==" et "[[" et "[" fonctionnent différemment et leur utilisation doit être cohérente.
michael
3
@michael_n: +1 pour cette remarque. D'un autre côté, j'adore les scripts, mais je trouve assez maladroit que la méthode portable soit de tester via [ "$var" = ".."]au lieu de ==, alors qu'en C il attribuerait au lieu de tester (et est une cause assez courante de bugs) ... pourquoi didn pas testutiliser à la ==place de =? quelqu'un sait?
Olivier Dulac
Voici également une drôle de chose que (au moins sur Kubuntu) la commande /usr/bin/[n'est pas un lien symbolique vers le /usr/bin/test, et plus encore: ces programmes ont même quelques tailles différentes!
Hi-Angel
Aussi: une seule parenthèse fermante )fait partie de la casesyntaxe de l' instruction pour terminer une ligne de casse. Il n'a pas de parenthèse ouvrante. Cela m'a jeté la première fois que je l'ai vu.
Agustín Amenabar
302

Supports

if [ CONDITION ]    Test construct  
if [[ CONDITION ]]  Extended test construct  
Array[1]=element1   Array initialization  
[a-z]               Range of characters within a Regular Expression
$[ expression ]     A non-standard & obsolete version of $(( expression )) [1]

[1] http://wiki.bash-hackers.org/scripting/obsolete

Accolades

${variable}                             Parameter substitution  
${!variable}                            Indirect variable reference  
{ command1; command2; . . . commandN; } Block of code  
{string1,string2,string3,...}           Brace expansion  
{a..z}                                  Extended brace expansion  
{}                                      Text replacement, after find and xargs

Parenthèses

( command1; command2 )             Command group executed within a subshell  
Array=(element1 element2 element3) Array initialization  
result=$(COMMAND)                  Command substitution, new style  
>(COMMAND)                         Process substitution  
<(COMMAND)                         Process substitution 

Parenthèses doubles

(( var = 78 ))            Integer arithmetic   
var=$(( 20 + 5 ))         Integer arithmetic, with variable assignment   
(( var++ ))               C-style variable increment   
(( var-- ))               C-style variable decrement   
(( var0 = var1<98?9:21 )) C-style ternary operation
Yola
la source
@Yola, pourriez-vous s'il vous plaît expliquer ce que fait $ (varname) exactement? Dans les projets Apple Xcode, je peux spécifier des chemins de fichier comme entrée / sortie de script. si je spécifie $ SRC_ROOT / myFile.txt ou $ {SRC_ROOT} /myFile.txt (la var SRC_ROOT est exportée par le système de construction) - ne fonctionne pas. seul $ (SRC_ROOT) /myFile.txt fonctionne. Quelle pourrait être la raison? clairement var nom n'est pas une commande?
Motti Shneor
1
@MottiShneor, dans votre cas $(varname)n'est pas lié à la syntaxe bash. Cela fait partie de la syntaxe Makefile .
Sasha
Ce n'est pas le cas - Xcode ne construit pas à l'aide de makefile et ses variables sont des variables d'environnement. Les processus propriétaires du système de construction Xcode lisent les valeurs de ces variables d'environnement prédéfinies. Les étapes de construction personnalisées ne sont que des scripts shell normaux (bash ou autre) et ont accès aux mêmes variables.
Motti Shneor
@MottiShneor, ok, affinons: cela fait probablement partie de la syntaxe xcconfig . Quoi qu'il en soit, $(varname)n'a aucun rapport avec la syntaxe bash dans votre cas.
Sasha
Vous ne mentionnez pas la différence entre la construction de test et la construction de test étendue.
Nikos
23

Je voulais juste ajouter ceux-ci à partir de TLDP :

~:$ echo $SHELL
/bin/bash

~:$ echo ${#SHELL}
9

~:$ ARRAY=(one two three)

~:$ echo ${#ARRAY}
3

~:$ echo ${TEST:-test}
test

~:$ echo $TEST


~:$ export TEST=a_string

~:$ echo ${TEST:-test}
a_string

~:$ echo ${TEST2:-$TEST}
a_string

~:$ echo $TEST2


~:$ echo ${TEST2:=$TEST}
a_string

~:$ echo $TEST2
a_string

~:$ export STRING="thisisaverylongname"

~:$ echo ${STRING:4}
isaverylongname

~:$ echo ${STRING:6:5}
avery

~:$ echo ${ARRAY[*]}
one two one three one four

~:$ echo ${ARRAY[*]#one}
two three four

~:$ echo ${ARRAY[*]#t}
one wo one hree one four

~:$ echo ${ARRAY[*]#t*}
one wo one hree one four

~:$ echo ${ARRAY[*]##t*}
one one one four

~:$ echo $STRING
thisisaverylongname

~:$ echo ${STRING%name}
thisisaverylong

~:$ echo ${STRING/name/string}
thisisaverylongstring
kzh
la source
18
Un esprit qui echo ${#ARRAY}affiche trois, à cause du premier élément du ARRAYcontient trois caractères, pas parce qu'il contient trois éléments! Pour imprimer le nombre d'éléments, utilisez echo ${#ARRAY[@]}.
TrueY
@zeal ${TEST:-test}est égal à $TESTsi la variable TESTexiste, sinon elle renvoie simplement la chaîne "test". Il existe une autre version qui fait encore plus: ${TEST:=test}--- qui équivaut également à $TESTsi TEST existe, mais chaque fois que cela n'existe pas, il crée la variable TESTet attribue une valeur "test" et devient également la valeur de l'expression entière.
Loves Probability
18

La différence entre test , [ et [[ est expliquée en détail dans le BashFAQ .

Pour faire court: test implémente l'ancienne syntaxe portable de la commande. Dans presque tous les shells (les plus anciens shells Bourne sont l'exception), [est synonyme de test (mais nécessite un argument final de]). Bien que tous les shells modernes aient des implémentations intégrées de [, il existe généralement toujours un exécutable externe de ce nom, par exemple / bin / [.

[[est une nouvelle version améliorée de celui-ci, qui est un mot-clé, pas un programme. Cela a des effets bénéfiques sur la facilité d'utilisation, comme indiqué ci-dessous. [[est compris par KornShell et BASH (par exemple 2.03), mais pas par les anciens POSIX ou BourneShell.

Et la conclusion:

Quand faut-il utiliser la nouvelle commande de test [[et quand l'ancienne [? Si la portabilité vers le BourneShell est un problème, l'ancienne syntaxe doit être utilisée. Si par contre le script nécessite BASH ou KornShell, la nouvelle syntaxe est beaucoup plus flexible.

fwhacking
la source
18

Parenthèses dans la définition de fonction

Les parenthèses ()sont utilisées dans la définition des fonctions:

function_name () { command1 ; command2 ; }

C'est la raison pour laquelle vous devez échapper les parenthèses même dans les paramètres de commande:

$ echo (
bash: syntax error near unexpected token `newline'

$ echo \(
(

$ echo () { command echo The command echo was redefined. ; }
$ echo anything
The command echo was redefined.
pabouk
la source
Oh, j'ai essayé le csh. Ma faute. Quand j'essaye bash, ça marche. Je ne connaissais pas la commande 'commande' de bash.
Chan Kim
comment puis-je annuler la redéfinition de la commande echo ()? (sans rouvrir le bash)
Chan Kim
2
@ChanKim: unset -f echo. Tu vois help unset.
pabouk
0
Truncate the contents of a variable

$ var="abcde"; echo ${var%d*}
abc

Make substitutions similar to sed

$ var="abcde"; echo ${var/de/12}
abc12

Use a default value

$ default="hello"; unset var; echo ${var:-$default}
hello
vuppala srikar
la source
Lorsque vous répondez à une question, ne visez pas seulement le "code", mais essayez également d'ajouter une explication ...
Mikev