Wir verwenden normalerweise $@
alle Argumente mit Ausnahme von $ 0. Ich weiß jedoch nicht, was Datenstruktur $@
ist.
Kann $*
mir jemand eine Erklärung auf Dolmetscherebene geben, warum es sich anders verhält, wenn es in doppelte Anführungszeichen eingeschlossen wird?
Es kann in der for-Schleife iteriert werden, es scheint also ein Array zu sein. Es kann aber auch ganz einfach wiedergegeben werden echo $@
, wenn es sich um ein Array handelt, nur das erste Element wird angezeigt. Aufgrund der Einschränkung der Shell kann ich keinen weiteren Testcode schreiben, um ihn auszuführen.
Unterschied zwischen diesem Beitrag : Dieser Beitrag zeigt, wie $@
sich anders verhält als $*
. Aber ich frage mich über den Datentyp von $@
. Shell als interpretierende Sprache sollte wie Python Daten nach einer Reihe grundlegender Typen darstellen. Oder mit anderen Worten, ich möchte wissen, wie $ @ im Computerspeicher gespeichert ist.
Ist es eine Zeichenfolge, eine mehrzeilige Zeichenfolge oder ein Array?
Wenn es sich um einen eindeutigen Datentyp handelt, kann eine benutzerdefinierte Variable als Instanz dieses Typs definiert werden?
printf '%s\n' "$@"
und testenprintf '%s\n' "$*"
. Dasecho
Dienstprogramm gibt nur die Argumente aus, unabhängig davon, ob es sich um eines oder mehrere handelt. Beide sind Arrays (von Strings), aber sie verhalten sich unterschiedlich, wenn sie in doppelte Anführungszeichen gesetzt werden. Wenn eine der beiden Zeichenfolgen mehrzeilig wäre, könnten sie keine mehrzeiligen Zeichenfolgen speichern (was auch möglich ist). Es ist unklar, welches Problem Sie lösen möchten.@var
Variable in Perl in Bezug auf den zugrunde liegenden Speicher darstellt. Aus der Sicht eines gewöhnlichen Perl-Programms spielt es keine Rolle, außer dass es als Array / Liste zugänglich ist (und die Tatsache, dass es Kontexte gibt, in denen eine Liste erwartet wird).Antworten:
Das begann als Hack in der Bourne-Shell. In der Bourne-Shell wurde die IFS-Wortteilung (nach der Tokenisierung) für alle Wörter im Listenkontext (Befehlszeilenargumente oder die Wörter, auf denen sich die
for
Schleife befindet) durchgeführt. Wenn du hättest:Diese zweite Linie in 3 Worten tokengekennzeichneten würde,
$var
erweitert werden würde, und Split + glob würde auf allen drei Worte geschehen, so würde Sie am Ende läufted
mitt
,f
,le.txt
,f
,le2.txt
als Argumente.Teile davon zu zitieren würde den Split + Glob verhindern. Die Bourne-Shell erinnerte sich anfangs daran, welche Zeichen in Anführungszeichen gesetzt wurden, indem sie das 8. Bit intern setzte (das änderte sich später, als Unix 8-Bit-sauber wurde, aber die Shell erinnerte sich noch an das angeführte Byte).
Beides
$*
und$@
war die Verkettung der Positionsparameter mit dem Zwischenraum. Aber es gab eine spezielle Verarbeitung von$@
Anführungszeichen. Wenn$1
enthaltenfoo bar
und$2
enthaltenbaz
,"$@"
würde erweitern auf:(wobei das
^
s oben angibt, für welches der Zeichen das 8. Bit gesetzt ist). Wobei das erste Leerzeichen in Anführungszeichen gesetzt wurde (wobei das 8. Bit gesetzt war), aber nicht das zweite (dasjenige, das zwischen den Wörtern hinzugefügt wurde).Und es ist die IFS-Aufteilung, die sich um die Trennung der Argumente kümmert (vorausgesetzt, das Leerzeichen ist so,
$IFS
wie es standardmäßig ist). Das ist ähnlich wie$*
bei seinem Vorgänger die Mashey-Shell (selbst basierend auf der Thomson-Shell, während die Bourne-Shell von Grund auf neu geschrieben wurde) erweitert wurde.Das erklärt, warum in der Bourne-Shell anfangs
"$@"
die leere Zeichenfolge statt gar nichts erweitert wurde, wenn die Liste der Positionsparameter leer war (Sie mussten damit umgehen${1+"$@"}
), warum die leeren Positionsparameter nicht"$@"
beibehalten wurden und warum nicht$IFS
funktioniert nicht, wenn das Leerzeichen nicht enthalten ist.Die Absicht war, die Liste der Argumente wörtlich an einen anderen Befehl weitergeben zu können, aber das funktionierte nicht richtig für die leere Liste, für leere Elemente oder wenn
$IFS
kein Leerzeichen vorhanden war (die ersten beiden Probleme wurden in späteren Versionen behoben) ).Die Korn-Shell (auf der die POSIX-Spezifikation basiert) hat dieses Verhalten auf verschiedene Arten geändert:
edit
oderfile.txt
im obigen Beispiel).$*
und$@
sind mit dem ersten Zeichen verbunden ist$IFS
oder , wenn Raum$IFS
ist leer , außer dass für eine zitiert"$@"
wird , dass wie in dem Tischler Bourne - Shell unquoted und für eine zitiert ,"$*"
wennIFS
leer ist , die Positionsparameter werden ohne Trennangehängt.${array[@]}
${array[*]}
erinnerte an Bourne$*
und$@
aber indice 0 anstelle von 1 beginnt und sparse (mehr wie assoziative Arrays) , die mittels$@
nicht wirklich als KSH Array behandelt werden kann (vergleiche mitcsh
/rc
/zsh
/fish
/yash
wo$argv
/$*
sind normale Arrays)."$@"
Wenn$#
0 ist, wird statt der leeren Zeichenfolge jetzt nichts mehr angezeigt. Funktioniert,"$@"
wenn$IFS
keine Leerzeichen enthalten sind, es sei denn, wennIFS
leer ist. Ein nicht in Anführungszeichen gesetztes$*
Argument ohne Platzhalterzeichen wird zu einem Argument erweitert (wobei die Positionsparameter mit einem Leerzeichen verbunden werden), wenn$IFS
es leer ist.ksh93 hat die verbleibenden Probleme oben behoben. In ksh93
$*
und wird$@
die Liste der Positionsparameter erweitert, unabhängig vom Wert von getrennt$IFS
und dann in Listenkontexten weiter aufgeteilt + globbed + geschweift-expandiert,$*
verbunden mit dem ersten Byte (nicht dem Zeichen) von$IFS
,"$@"
in Listenkontexten wird die Liste erweitert von Positionsparametern, unabhängig vom Wert von$IFS
. In Nicht-Listenkontext wie invar=$@
,$@
mit Raum verbunden , unabhängig vom Wert von$IFS
.bash
Die Arrays sind nach den ksh-Arrays entworfen. Die Unterschiede sind:$IFS
anstelle von für Byte$*
wenn im Kontext, in dem keine Liste vorhanden$IFS
ist, keine Anführungszeichen vorhanden sind, wenn leer.Während die POSIX-Spezifikation früher ziemlich vage war, gibt sie jetzt mehr oder weniger das Bash-Verhalten an.
Es unterscheidet sich von normalen Arrays darin
ksh
oderbash
darin:"${@:0}"
Includes$0
(kein Positionsparameter, und bei Funktionen wird der Name der Funktion angegeben oder nicht, abhängig von der Shell und der Definition der Funktion)).shift
kann verwendet werden.In
zsh
oderyash
wo Arrays normale Arrays sind (nicht spärlich, Indizes beginnen wie in allen anderen Shells mit Ausnahme von ksh / bash bei einem),$*
wird als normales Array behandelt.zsh
hat$argv
als Alias dafür (aus Kompatibilitätsgründen mitcsh
).$*
ist dasselbe wie$argv
oder${argv[*]}
(Argumente, die mit dem ersten Zeichen von verbunden sind,$IFS
aber dennoch in Listenkontexten getrennt sind)."$@"
mag"${argv[@]}"
oder"${*[@]}"}
unterzieht sich der Korn-artigen Sonderverarbeitung.quelle
Es ist ein spezieller Parameter, der sich zu den Werten der Positionsparameter erweitert ... Aber das ist keine Frage der Terminologie.
Wir können die Positionsparameter als Teile von betrachten
$@
, so dass sie eine Reihe von unterschiedlichen Elementen ($1
,$2
...) haben, auf die unabhängig zugegriffen werden kann und die durch aufeinanderfolgende natürliche Zahlen benannt sind. Das macht es zu etwas, das normalerweise als Array bezeichnet wird.Die Syntax ist allerdings etwas seltsam und sogar begrenzt. Es gibt keine Möglichkeit, ein einzelnes Element des Arrays einzeln zu ändern. Stattdessen muss das Ganze auf einmal eingestellt werden. (Sie können
set -- "$@" foo
einen Wert anhängen oderset -- "${@:1:2}" foo "${@:3}"
einen Wert in der Mitte hinzufügen. In beiden Fällen müssen Sie jedoch die gesamte resultierende Liste ausschreiben.)Weil sie so definiert sind, dass sie sich anders verhalten.
Wenn Sie die Tatsache meinen, dass
a=(foo bar asdf); echo $a
nur ausgegeben wirdfoo
, dann handelt es sich meistens um eine Eigenart der Shell-Syntax und die Tatsache, dass benannte Arrays im ksh-Stil später als die Positionsparameter und erstellt wurden$@
. Einfach$a
ist das Gleiche,${a[0]}
also hat es die abwärtskompatible Bedeutung eines einzelnen Skalarwerts, unabhängig davon, oba
es sich um ein Array oder eine einfache Skalarvariable handelt.Das
@
Zeichen, das sich auf die gesamte Liste bezieht, wurde mit benannten Arrays wiederverwendet"${a[@]}"
, um die gesamte Liste zu erhalten. Im Vergleich zu benannten Arrays mit$@
werden die unnötigen Klammern und der Name einfach übersprungen.Das hängt von der Implementierung ab. Sie müssen sich den Quellcode einer bestimmten Shell ansehen, die Sie interessiert.
Meistens ein Array. Obwohl sie sich von den ksh-artigen benannten Arrays unterscheiden, können sie beliebige nichtnegative Ganzzahlen als Indizes haben, nicht nur aufeinanderfolgende wie bei
$@
. (Das heißt, kann ein benanntes Array spärlich sein, und hat zum Beispiel des Indizes1
,3
und4
mit0
und2
fehlt. Das ist nicht möglich , mit den Positionsparametern.)Es ist keine einzelne Zeichenfolge, da sie zu verschiedenen Elementen erweitert werden kann, und das Aufrufen der
$@
Zeilenelemente ist auch nicht richtig, da jede reguläre Variable oder einer der Positionsparameter (Elemente von ) auch Zeilenumbrüche enthalten kann.Nein. Aber benannte Arrays sind wahrscheinlich sowieso nützlicher.
quelle
$@
ist keine Datenstruktur, sondern eine von wenigen Funktionen / Operatoren zum Erweitern der Positionsparameter-Datenstruktur.