Cela a commencé comme un hack dans le shell Bourne. Dans le shell Bourne, le fractionnement des mots IFS a été effectué (après la tokenisation) sur tous les mots dans le contexte de la liste (arguments de ligne de commande ou les mots sur lesquels les forboucles bouclent). Si tu avais:
IFS=i var=file2.txt
edit file.txt $var
Cette deuxième ligne serait en 3 mots en jetons, $varserait élargi, et divisé + glob serait fait sur les trois mots, de sorte que vous finiriez en cours d' exécution edavec t, f, le.txt, f, le2.txtcomme arguments.
Citer des parties de cela empêcherait le split + glob. Le shell Bourne se souvenait initialement des caractères cités en définissant le 8ème bit sur eux en interne (cela a changé plus tard lorsque Unix est devenu propre à 8 bits, mais le shell a toujours fait quelque chose de similaire pour se rappeler quel octet a été cité).
Les deux $*et $@étaient la concaténation des paramètres de position avec l'espace entre les deux. Mais il y avait un traitement spécial de l' $@intérieur des guillemets doubles. S'ils $1étaient contenus foo baret $2contenus baz, "$@"s'étendraient à:
foo bar baz
^^^^^^^ ^^^
(les ^s ci-dessus indiquant lesquels des caractères ont le 8ème bit défini). Où le premier espace a été cité (avait le 8ème bit défini) mais pas le second (celui ajouté entre les mots).
Et c'est le fractionnement IFS qui s'occupe de séparer les arguments (en supposant que le caractère espace est $IFScomme il est par défaut). C'est similaire à la façon dont a $*été développé dans son prédécesseur le shell Mashey (lui-même basé sur le shell Thomson, tandis que le shell Bourne a été écrit à partir de zéro).
Cela explique pourquoi dans le shell Bourne "$@"se développerait initialement dans la chaîne vide au lieu de rien du tout lorsque la liste des paramètres de position était vide (vous deviez le contourner ${1+"$@"}), pourquoi il n'a pas conservé les paramètres de position vides et pourquoi "$@"n'a pas $IFSne fonctionne pas quand ne contient pas le caractère espace.
L'intention était de pouvoir passer la liste des arguments textuellement à une autre commande, mais cela ne fonctionnait pas correctement pour la liste vide, pour les éléments vides ou quand $IFSne contenait pas d'espace (les deux premiers problèmes ont finalement été corrigés dans les versions ultérieures ).
Le shell Korn (sur lequel la spécification POSIX est basée) a modifié ce comportement de plusieurs manières:
- Le fractionnement IFS ne se fait que sur le résultat d'expansions sans guillemets (pas sur des mots littéraux comme
editou file.txtdans l'exemple ci-dessus)
$*et $@sont joints avec le premier caractère de $IFSou espace quand $IFSest vide sauf que pour un guillemet "$@", ce menuisier n'est pas entre guillemets comme dans le shell Bourne, et pour un guillemet "$*"quand IFSest vide, les paramètres de position sont ajoutés sans séparateur.
- il a ajouté un support pour les tableaux, et avec des
${array[@]} ${array[*]}réminiscences de Bourne $*et $@mais commençant à l'indice 0 au lieu de 1, et clairsemé (plus comme des tableaux associatifs) ce qui signifie $@qu'il ne peut pas vraiment être traité comme un tableau ksh (comparer avec csh/ rc/ zsh/ fish/ yashoù $argv/ $*sont normaux tableaux).
- Les éléments vides sont conservés.
"$@"quand $#est 0 se développe maintenant à rien au lieu de la chaîne vide, "$@"fonctionne quand $IFSne contient pas d'espaces sauf quand IFSest vide. Un $*caractère sans guillemets sans caractères génériques se développe en un seul argument (où les paramètres de position sont joints à l'espace) lorsqu'il $IFSest vide.
ksh93 a résolu les quelques problèmes restants ci-dessus. Dans ksh93, $*et se $@développe dans la liste des paramètres de position, séparés indépendamment de la valeur de $IFS, puis se divise davantage + globbed + accolade-développé dans les contextes de liste, $*joint avec le premier octet (pas de caractère) de $IFS, "$@"dans les contextes de liste se développe dans la liste des paramètres de position, quelle que soit la valeur de $IFS. Dans un contexte sans liste, comme dans var=$@, $@est joint à l'espace quelle que soit la valeur de $IFS.
bashLes tableaux de sont conçus après ceux de ksh. Les différences sont les suivantes:
- aucune accolade-expansion lors d'une expansion non cotée
- premier caractère de
$IFSau lieu de pour octet
- certaines différences de cas d'angle comme l'expansion de
$*quand non-cité dans un contexte non-liste quand $IFSest vide.
Alors que la spécification POSIX était assez vague, elle spécifie maintenant plus ou moins le comportement de bash.
C'est différent des tableaux normaux dans kshou bashen ce que:
- Les indices commencent à 1 au lieu de 0 (sauf dans
"${@:0}"ce qui inclut $0(pas un paramètre positionnel, et dans les fonctions vous donne le nom de la fonction ou non selon le shell et comment la fonction a été définie)).
- Vous ne pouvez pas attribuer des éléments individuellement
- ce n'est pas rare, vous ne pouvez pas supprimer les éléments individuellement
shift peut être utilisé.
Dans zshou yashoù les tableaux sont des tableaux normaux (pas clairsemés, les indices commencent à un comme dans tous les autres shells mais ksh / bash), $*est traité comme un tableau normal. zsha $argvcomme alias (pour compatibilité avec csh). $*est identique à $argvor ${argv[*]}(arguments joints au premier caractère de $IFSmais toujours séparés dans les contextes de liste). "$@"comme "${argv[@]}"ou "${*[@]}"}subit le traitement spécial de style Korn.