Nous utilisons habituellement $@
pour représenter tous les arguments sauf $ 0. Cependant, je ne sais pas ce qu'est la structure des données $@
.
Pourquoi cela se comporte-t-il différemment avec l' $*
inclusion de guillemets doubles, est-ce que quelqu'un pourrait me donner une explication de niveau interprète?
Il peut être itéré dans la boucle for, il semble donc être un tableau. Cependant, il peut également résonner entièrement avec simple echo $@
, s'il s'agit d'un tableau, seul le premier élément sera affiché. En raison de la limitation du shell, je ne peux pas écrire plus de code d'expérience pour le réaliser.
Différence entre ce post : Ce post montre comment $@
se comporte différemment de $*
. Mais je me pose des questions sur le type de données de $@
. Shell en tant que langage d'interprétation, comme Python, devrait représenter les données selon une série de types fondamentaux. Ou en d'autres termes, je veux savoir comment $ @ est stocké dans la mémoire de l'ordinateur.
Est-ce une chaîne, une chaîne multi-lignes ou un tableau?
S'il s'agit d'un type de données unique, est-il possible de définir une variable personnalisée comme instance de ce type?
printf '%s\n' "$@"
etprintf '%s\n' "$*"
. L'echo
utilitaire sort simplement ses arguments, qu'ils soient un ou plusieurs. Les deux sont des tableaux (de chaînes), mais ils se comportent différemment lorsqu'ils sont entre guillemets. Si l'une ou l'autre était une chaîne multiligne, alors ils ne seraient pas en mesure de stocker des chaînes multilignes (ce qu'ils peuvent). On ne sait pas quel problème vous essayez de résoudre.@var
variable en Perl, en termes de stockage sous-jacent. Du point de vue d'un programme Perl ordinaire, cela n'a pas vraiment d'importance, sinon qu'il est accessible en tant que tableau / liste (et le fait qu'il existe des contextes dans lesquels une liste est attendue).Réponses:
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
for
boucles bouclent). Si tu avais:Cette deuxième ligne serait en 3 mots en jetons,
$var
serait élargi, et divisé + glob serait fait sur les trois mots, de sorte que vous finiriez en cours d' exécutioned
avect
,f
,le.txt
,f
,le2.txt
comme 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 contenusfoo bar
et$2
contenusbaz
,"$@"
s'étendraient à:(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
$IFS
comme 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$IFS
ne 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
$IFS
ne 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:
edit
oufile.txt
dans l'exemple ci-dessus)$*
et$@
sont joints avec le premier caractère de$IFS
ou espace quand$IFS
est vide sauf que pour un guillemet"$@"
, ce menuisier n'est pas entre guillemets comme dans le shell Bourne, et pour un guillemet"$*"
quandIFS
est vide, les paramètres de position sont ajoutés sans séparateur.${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 aveccsh
/rc
/zsh
/fish
/yash
où$argv
/$*
sont normaux tableaux)."$@"
quand$#
est 0 se développe maintenant à rien au lieu de la chaîne vide,"$@"
fonctionne quand$IFS
ne contient pas d'espaces sauf quandIFS
est 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$IFS
est 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 dansvar=$@
,$@
est joint à l'espace quelle que soit la valeur de$IFS
.bash
Les tableaux de sont conçus après ceux de ksh. Les différences sont les suivantes:$IFS
au lieu de pour octet$*
quand non-cité dans un contexte non-liste quand$IFS
est 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
ksh
oubash
en ce que:"${@: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)).shift
peut être utilisé.Dans
zsh
ouyash
où 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.zsh
a$argv
comme alias (pour compatibilité aveccsh
).$*
est identique à$argv
or${argv[*]}
(arguments joints au premier caractère de$IFS
mais toujours séparés dans les contextes de liste)."$@"
comme"${argv[@]}"
ou"${*[@]}"}
subit le traitement spécial de style Korn.la source
C'est un paramètre spécial qui se développe aux valeurs des paramètres de position ... Mais c'est une tergiversation sur la terminologie.
Nous pouvons voir les paramètres positionnels comme des parties de
$@
, donc il a un certain nombre d'éléments distincts ($1
,$2
...), qui peuvent être accédés indépendamment et sont nommés par des nombres naturels consécutifs. Cela en fait quelque chose qui est généralement appelé un tableau.La syntaxe est cependant un peu bizarre et même limitée. Il n'y a aucun moyen de modifier un seul élément du tableau individuellement. Au lieu de cela, le tout doit être réglé en même temps. (Vous pouvez utiliser
set -- "$@" foo
pour ajouter une valeur, ouset -- "${@:1:2}" foo "${@:3}"
pour ajouter une valeur au milieu. Mais dans les deux cas, vous devez écrire toute la liste résultante.)Parce qu'ils sont définis pour se comporter différemment.
Si vous voulez dire le fait que la
a=(foo bar asdf); echo $a
sortie sera justefoo
, alors c'est principalement une bizarrerie de la syntaxe du shell, et le fait que les tableaux nommés de style ksh ont été créés plus tard que les paramètres positionnels et$@
. Plain$a
est le même que${a[0]}
s'il a la signification rétrocompatible d'une seule valeur scalaire, qu'il s'agisse d'a
un tableau ou d'une simple variable scalaire.Le
@
signe se référant à la liste entière a été réutilisé avec des tableaux nommés dans"${a[@]}"
la manière d'obtenir la liste entière. Par rapport aux tableaux nommés, avec$@
, les accolades et crochets inutiles et le nom sont simplement ignorés.Cela dépend de l'implémentation, vous devrez regarder le code source de tout shell particulier qui vous intéresse.
Un tableau, surtout. Bien qu'ils soient différents des tableaux nommés de style ksh, car ils peuvent avoir des entiers non négatifs arbitraires comme index, pas seulement des entiers consécutifs comme avec
$@
. (Autrement dit, un tableau nommé peut être clairsemé et avoir, par exemple, les index1
,3
et4
, avec0
et2
manquant. Ce n'est pas possible avec les paramètres de position.)Ce n'est pas une chaîne unique, car elle peut être étendue à des éléments distincts, et appeler les lignes d'éléments n'est pas non plus correct, car toute variable régulière ou l'un des paramètres de position (éléments de
$@
) peut également contenir des retours à la ligne.Non. Mais les tableaux nommés sont probablement plus utiles de toute façon.
la source
$@
n'est pas une structure de données, c'est l'une des quelques fonctions / opérateurs pour étendre la structure de données des paramètres de position.