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:
IFS=i var=file2.txt
edit file.txt $var
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äuft ed
mit t
, 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
enthalten foo bar
und $2
enthalten baz
, "$@"
würde erweitern auf:
foo bar baz
^^^^^^^ ^^^
(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:
- Die IFS-Aufteilung wird nur für das Ergebnis nicht zitierter Erweiterungen durchgeführt (nicht für wörtliche Wörter wie
edit
oder file.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 , "$*"
wenn IFS
leer ist , die Positionsparameter werden ohne Trennangehängt.
- es zusätzliche Unterstützung für Arrays und mit
${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 mit csh
/ rc
/ zsh
/ fish
/ yash
wo $argv
/ $*
sind normale Arrays).
- Die leeren Elemente bleiben erhalten.
"$@"
Wenn $#
0 ist, wird statt der leeren Zeichenfolge jetzt nichts mehr angezeigt. Funktioniert, "$@"
wenn $IFS
keine Leerzeichen enthalten sind, es sei denn, wenn IFS
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 in var=$@
, $@
mit Raum verbunden , unabhängig vom Wert von $IFS
.
bash
Die Arrays sind nach den ksh-Arrays entworfen. Die Unterschiede sind:
- Keine Klammererweiterung bei nicht zitierter Erweiterung
- erstes Zeichen von
$IFS
anstelle von für Byte
- Einige Unterschiede in der Groß- und Kleinschreibung, wie z. B. die Erweiterung von,
$*
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
oder bash
darin:
- Indizes beginnen bei 1 anstelle von 0 (außer bei
"${@: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)).
- Sie können Elemente nicht einzeln zuweisen
- Es ist nicht spärlich, Sie können Elemente nicht einzeln entfernen
shift
kann verwendet werden.
In zsh
oder yash
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 mit csh
). $*
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.