Réponse courte: utilisez"$@"
(notez les guillemets). Les autres formes sont très rarement utiles.
"$@"
est une syntaxe assez étrange. Il est remplacé par tous les paramètres de position, sous forme de champs distincts. S'il n'y a pas de paramètre de position ( $#
vaut 0), alors se "$@"
développe jusqu'à rien (pas une chaîne vide, mais une liste avec 0 éléments), s'il existe un paramètre de position "$@"
équivalent à "$1"
, s'il existe deux paramètres de position "$@"
équivalent à "$1" "$2"
, etc.
"$@"
vous permet de transmettre les arguments d'un script ou d'une fonction à une autre commande. Il est très utile pour les wrappers effectuant des tâches telles que la définition de variables d'environnement, la préparation de fichiers de données, etc. avant d'appeler une commande avec les mêmes arguments et options que ceux utilisés pour le wrapper.
Par exemple, la fonction suivante filtre la sortie de cvs -nq update
. Outre le filtrage de sortie et le statut de retour (qui est celui de grep
plutôt que celui de cvs
), l'appel cvssm
de certains arguments se comporte comme un appel cvs -nq update
avec ces arguments.
cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }
"$@"
étend à la liste des paramètres de position. Dans les shells qui prennent en charge les tableaux, il existe une syntaxe similaire pour développer la liste des éléments du tableau: "${array[@]}"
(les accolades sont obligatoires sauf dans zsh). Là encore, les guillemets doubles sont quelque peu trompeurs: ils protègent contre la division des champs et la génération de motifs des éléments du tableau, mais chaque élément du tableau se termine dans son propre champ.
Certains anciens coquillages avaient ce qu’on pourrait appeler un bogue: quand il n’y avait pas d’arguments de position, ils étaient "$@"
étendus à un seul champ contenant une chaîne vide plutôt qu’à aucun champ. Cela a conduit à la solution de contournement${1+"$@"}
(rendue célèbre via la documentation Perl ). Seules les versions plus anciennes du shell Bourne et de l'implémentation OSF1 sont concernées, aucun de ses remplacements compatibles actuels (ash, ksh, bash,…) ne le sont. /bin/sh
n'est pas affecté par les systèmes publiés au 21ème siècle que je connaisse (à moins que vous ne comptiez la version de maintenance Tru64, et même s'il /usr/xpg4/bin/sh
existe en toute sécurité, seuls les #!/bin/sh
scripts sont affectés, pas les #!/usr/bin/env sh
scripts tant que votre PATH est configuré pour la conformité POSIX) . En bref, il s’agit d’une anecdote historique dont vous ne devez pas vous inquiéter.
"$*"
s'étend toujours à un mot. Ce mot contient les paramètres de position, concaténés avec un espace entre eux. (Plus généralement, le séparateur est le premier caractère de la valeur de la IFS
variable. Si la valeur de IFS
est la chaîne vide, le séparateur est la chaîne vide.) S'il n'y a pas de paramètre de position, "$*"
la chaîne est vide, s'il y en a deux paramètres de position et IFS
sa valeur par défaut est alors "$*"
équivalente à "$1 $2"
, etc.
$@
et les $*
citations extérieures sont équivalentes. Ils développent la liste des paramètres de position, sous forme de champs séparés, comme "$@"
; mais chaque champ résultant est ensuite divisé en champs distincts qui sont traités comme des modèles de caractère générique de nom de fichier, comme d'habitude avec les extensions de variable non citées.
Par exemple, si le répertoire actuel contient trois fichiers bar
, baz
et foo
alors:
set -- # no positional parameters
for x in "$@"; do echo "$x"; done # prints nothing
for x in "$*"; do echo "$x"; done # prints 1 empty line
for x in $*; do echo "$x"; done # prints nothing
set -- "b* c*" "qux"
echo "$@" # prints `b* c* qux`
echo "$*" # prints `b* c* qux`
echo $* # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`