Accès à la ligne de commande bash args $ @ vs $ *

327

Dans de nombreuses questions SO et didacticiels bash, je constate que je peux accéder aux arguments de ligne de commande dans les scripts bash de deux manières:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

Ce qui se traduit par:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

Quelle est la difference entre $*et $@?
Quand faut-il utiliser la première et quand doit-on utiliser la seconde?

Oz123
la source
jetez un oeil à cette réponse: stackoverflow.com/a/842325/671366
codeling
l'analyse statique dans IntelliJ traite echo "something $@"comme une erreur
Alex Cohn

Réponses:

437

La différence apparaît lorsque les paramètres spéciaux sont cités. Permettez-moi d'illustrer les différences:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

un autre exemple sur l'importance de la citation: notez qu'il y a 2 espaces entre "arg" et le nombre, mais si je ne cite pas $ word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

et en bash, "$@"est la liste "par défaut" sur laquelle itérer:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3
glenn jackman
la source
65
+1 J'ai toujours pensé que ce concept était mieux illustré par un exemple simple, dans lequel le manuel bash fait complètement défaut.
chepner
5
Y a-t-il un cas d'utilisation possible, quand $*ou "$*"peut être requis, et l'objectif ne peut pas être atteint par $@ou "$@"?
anishsane
5
Quelle version est la plus appropriée pour un script "wrapper", où les paramètres des scripts doivent devenir des paramètres pour une nouvelle commande?
Segfault
7
@Segfault, dans ce cas, choisissez toujours "$@"avec les guillemets.
glenn jackman
2
Cette réponse contient des exemples utiles mais serait mieux si elle expliquait également le mécanisme derrière eux. Pourquoi ça marche comme ça?
Lii
255

Un joli tableau de présentation pratique du wiki Bash Hackers :

$ * contre $ @ table

cdans la troisième ligne est le premier caractère de $IFS, le séparateur de champ interne, une variable shell.

Si les arguments doivent être stockés dans une variable de script et que les arguments doivent contenir des espaces, je recommande sans réserve d'employer une "$*"astuce avec le séparateur de champ interne $IFSdéfini sur tab .

Serge Stroobandt
la source
42
... où "c" est le premier caractère de $ IFS
glenn jackman
39
... et $IFSsignifie "Séparateur de champ interne".
Serge Stroobandt
Voici un exemple , qui comprend une entrée entre guillemets. L'entrée est également importante!
Serge Stroobandt
Disons que je veux créer un script wrapper qui ne fait que reproduire la fonctionnalité de la commande wrappée. Quelle syntaxe dois-je utiliser pour passer les arguments du script wrapper à la commande interne?
Marinos Un
44

$ *

S'étend aux paramètres positionnels, en commençant par un. Lorsque l'expansion se produit entre guillemets, elle se développe en un seul mot avec la valeur de chaque paramètre séparée par le premier caractère de la variable spéciale IFS. Autrement dit, "$ *" équivaut à "$ 1c $ 2c ...", où c est le premier caractère de la valeur de la variable IFS. Si IFS n'est pas défini, les paramètres sont séparés par des espaces. Si IFS est nul, les paramètres sont joints sans séparateurs intermédiaires.

$ @

S'étend aux paramètres positionnels, en commençant par un. Lorsque l'expansion se produit entre guillemets doubles, chaque paramètre se développe en un mot distinct. Autrement dit, "$ @" est équivalent à "$ 1" "$ 2" ... Si l'expansion entre guillemets se produit dans un mot, l'expansion du premier paramètre est jointe à la partie de début du mot d'origine et l'expansion du dernier paramètre est joint à la dernière partie du mot d'origine. Lorsqu'il n'y a pas de paramètres de position, "$ @" et $ @ se développent à rien (c'est-à-dire qu'ils sont supprimés).

Source: Bash man

Muffo
la source
15

$ @ est identique à $ *, mais chaque paramètre est une chaîne entre guillemets, c'est-à-dire que les paramètres sont transmis intacts, sans interprétation ni expansion. Cela signifie, entre autres, que chaque paramètre de la liste d'arguments est considéré comme un mot distinct.

Bien sûr, "$ @" doit être cité.

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST

rkosegi
la source
1

Cet exemple peut mettre en évidence la différence entre "at" et "asterix" pendant que nous les utilisons. J'ai déclaré deux tableaux "fruits" et "légumes"

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

Voir le résultat suivant le code ci-dessus:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion
Stefansson
la source
7
Scientifiquement parlant, les tomates sont des fruits.
Randy
1
Tu as raison! "En botanique, un fruit est la structure porteuse de graines des plantes à fleurs (également appelées angiospermes) formées à partir de l'ovaire après la floraison." en.wikipedia.org/wiki/Fruit
stefansson
@Randy: scientifiquement parlant, tous les fruits sont des légumes (c'est un synonyme de "plante").
Cris Luengo
@CrisLuengo hérésie! :)
Randy