Que signifie $ @ dans un script shell?

Réponses:

263

$@correspond à tous les paramètres passés au script.

Par exemple, si vous appelez, ./someScript.sh foo baralors $@sera égal à foo bar.

Si tu fais:

./someScript.sh foo bar

puis someScript.shréférence intérieure :

umbrella_corp_options "$@"

celui-ci sera transmis umbrella_corp_optionsavec chaque paramètre individuel entre guillemets, permettant de prendre des paramètres avec un espace vide de l'appelant et de les transmettre.

Har
la source
1
Que contiendrait $ @ si je le faisais someScript.sh foo bar "boo far"?
trusktr
7
$ @ est spécial s'il est écrit entre guillemets. Ensuite, il en résultera une liste de valeurs entre guillemets, dans votre cas, trusktr, dans les trois arguments "foo", "bar" et "boo far".
Alfe
5
Bien que ce soit généralement le cas, $@ne vient pas nécessairement des paramètres passés au script ... par exemple; set a b "x   y"; printf '(%s)' "$@"sorties(a)(b)(x   y)
Peter.O
2
J'aime mieux la réponse d'Alfe parce qu'il donne la principale différence entre $@et$*
donleyp
114

$@est presque le même que $*, les deux signifiant "tous les arguments de ligne de commande". Ils sont souvent utilisés pour simplement passer tous les arguments à un autre programme (formant ainsi une enveloppe autour de cet autre programme).

La différence entre les deux syntaxes apparaît lorsque vous avez un argument avec des espaces (par exemple) et mis $@entre guillemets:

wrappedProgram "$@"
# ^^^ this is correct and will hand over all arguments in the way
#     we received them, i. e. as several arguments, each of them
#     containing all the spaces and other uglinesses they have.
wrappedProgram "$*"
# ^^^ this will hand over exactly one argument, containing all
#     original arguments, separated by single spaces.
wrappedProgram $*
# ^^^ this will join all arguments by single spaces as well and
#     will then split the string as the shell does on the command
#     line, thus it will split an argument containing spaces into
#     several arguments.

Exemple: appel

wrapper "one two    three" four five "six seven"

aura pour résultat:

"$@": wrappedProgram "one two    three" four five "six seven"
"$*": wrappedProgram "one two    three four five six seven"
                             ^^^^ These spaces are part of the first
                                  argument and are not changed.
$*:   wrappedProgram one two three four five six seven
Alfe
la source
2
Ce ne sont pas les mêmes, et la page de manuel est claire sur les effets secondaires de $ * en utilisant IFS - qui n'est pas nécessairement un espace. (S'ils étaient les mêmes, il n'y aurait aucun intérêt, autre que la compatibilité peut-être, à offrir les deux.)
jørgensen
7
Non ils ne sont pas. Et je l'ai dit deux lignes ci-dessous: "La différence entre les deux ..." Pour obtenir des phrases courtes et améliorer la lisibilité, le lecteur doit lire plus d'une phrase avant de rendre un verdict: - /
Alfe
2
Alfe, l'insertion par Christoffer de ce mot «presque» a fait une sacrée différence, sans sacrifier aucune lacune ni lisibilité. En fait, j'ai voté pour cette réponse (par opposition à celle acceptée) exactement en raison de cette subtile accentuation de la différence ... - avant de réaliser que c'était presque contre votre volonté! ;)
Sz.
Je pense que ce mot a fait une sacrée différence pour les gens qui ont rendu un verdict juste après avoir lu la première phrase ;-) et cela n'a jamais été contre ma volonté. J'aimerais vraiment écrire aussi pour ces personnes.
Alfe
Très peu clair. wrappedProgram "$*"-> separated by single spaces.mais dans votre 2ème exemple, ils ne sont pas séparés par des espaces simples.
Felix Dombek
39

Voici les arguments de ligne de commande où:

$@= stocke tous les arguments dans une liste de chaînes
$*= stocke tous les arguments sous forme de chaîne unique
$#= stocke le nombre d'arguments

Sameer Duwal
la source
(L'inexactitude ci-dessus mentionnée par @iruvar a été corrigée.)
Mateen Ulhaq
13

L'utilisation d'un $@moyen pur dans la plupart des cas "fait mal au programmeur aussi fort que vous le pouvez", car dans la plupart des cas, cela conduit à des problèmes de séparation des mots et d'espaces et autres caractères dans les arguments.

Dans (supposé) 99% de tous les cas, il est nécessaire de l'inclure dans ": "$@"est ce qui peut être utilisé pour itérer de manière fiable sur les arguments.

for a in "$@"; do something_with "$a"; done
glglgl
la source
4
Votre ligne peut être écrite comme suit: pour a; faire quelque chose_avec "$ a"; done ;-)
Alfe
1
@Alfe je sais; je déteste juste ça. Pensez-y comme for a in start_token "$@" end_token; do something_with "$a"; done:-)
glglgl
9

À partir du manuel:

@

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

Christoffer Hammarström
la source
1

Sens.

En bref, $@s'étend aux arguments positionnels passés de l'appelant à une fonction ou à un script . Sa signification dépend du contexte : à l'intérieur d'une fonction, elle s'étend aux arguments passés à une telle fonction. S'il est utilisé dans un script (pas dans la portée d'une fonction), il s'étend aux arguments passés à ce script.

$ cat my-sh
#! /bin/sh
echo "$@"

$ ./my-sh "Hi!"
Hi!
$ put () ( echo "$@" )
$ put "Hi!"
Hi!

Partage de mots.

Maintenant, un autre sujet qui est d'une importance primordiale pour comprendre comment $@se comporte dans le shell est le fractionnement de mots . Le shell divise les jetons en fonction du contenu de la IFSvariable. Sa valeur par défaut est \t\n; c'est-à-dire, espace blanc, tabulation et nouvelle ligne.

L'expansion "$@"vous donne une copie parfaite des arguments passés. Cependant, l'expansion $@ne le sera pas toujours. Plus précisément, si les arguments contiennent des caractères de IFS, ils seront séparés.


La plupart du temps, ce que vous voudrez utiliser ne l'est "$@"pas $@.

luis lavaire
la source