Die Wortaufteilung gilt nur für nicht zitierte Erweiterungen (Parametererweiterung, arithmetische Erweiterung und Befehlssubstitution) in modernen Bourne-ähnlichen Shells (in zsh
, nur Befehlssubstitution, sofern Sie keinen Emulationsmodus verwenden).
Wenn Sie das tun:
args a :b
Wortaufteilung ist überhaupt nicht beteiligt.
Es ist die Shell-Analyse, die diese tokenisiert, feststellt, dass das erste nicht eines seiner Schlüsselwörter ist, und daher ist es ein einfacher Befehl mit 3 Argumenten : args
, a
und :b
. Der Platz macht dort keinen Unterschied. Beachten Sie, dass es sich nicht nur um Leerzeichen, sondern auch um Tabulatoren und in einigen Shells (wie yash
oder bash
) um Zeichen handelt, die in Ihrem Gebietsschema als leer betrachtet werden (im Fall von bash
nicht den Multibyte- Zeichen ) ¹.
Auch in dem Bourne - Shell , wo einzelnen Worte aufgespalten auch nicht notierten Argumente von Befehlen unabhängig davon angewandt , ob sie das Ergebnis der Erweiterungen waren oder nicht, die getan werden würde auf der Oberseite (lange nach) den tokenising und Syntax - Analyse.
In der Bourne-Shell
IFS=i
while bib=did edit foo
Das würde das nicht analysieren als:
"wh" "le b" "b=d" "d ed" "t foo"
Aber erst als while
mit einem einfachen Befehl und das edit
Wort (wie es ist ein Argument , aber nicht das bid=did
Wort , das eine Zuordnung ist) dieser einfache Befehl würde weiter aufgeteilt in ed
und t
so , dass der ed
Befehl mit den drei Argumenten ed
, t
und foo
als die ausgeführt werden würde Zustand dieser while
Schleife.
Die Wortaufteilung ist nicht Teil der Syntaxanalyse. Es ist wie ein Operator, der implizit auf Argumente (auch in for
Schleifenwörtern, Arrays und mit einigen Shell das Ziel von Umleitungen und einigen anderen Kontexten ) für die Teile von ihnen angewendet wird , die nicht in Anführungszeichen stehen. Was verwirrend ist, ist, dass es implizit gemacht wird . Sie tun es nicht cmd split($x)
, Sie tun es cmd $x
und das split()
( tatsächlichglob(split())
) ist impliziert. In zsh
müssen Sie es explizit für Parametererweiterungen anfordern ( split($x)
ist $=x
da ( $=
sieht aus wie eine Schere)).
Nun zu Ihren Beispielen:
args(){ echo ["$*"];}
args a :b # three spaces
# [a::b]
a
und :b
Argumente args
mit dem ersten Zeichen verbunden $IFS
die gibt a::b
(beachten Sie, dass es eine schlechte Idee, mit [...]
hier , wie es ist ein Globbing Operator).
args(){ echo [$*];}
args a :b # three spaces
# [a b] # two spaces
$*
(was enthält a::b
) wird aufgeteilt in a
die leere Zeichenfolge und b
. So ist es:
echo '[a' '' 'b]'
args(){ echo ["$1"]["$2"]; }
args a :b # three spaces
# [a][:b]
Kein Wunder, da es keine Wortspaltung gibt.
args(){ echo [$1][$2]; }
args a :b # three spaces
# [a][ b]
Das ist wie:
echo '[a]' '[' 'b]'
as $2
( :b
) würde in die leere Zeichenfolge und aufgeteilt b
.
Ein Fall, in dem Sie Abweichungen zwischen den Implementierungen feststellen, ist, wenn er $IFS
leer ist.
Im:
set a b
IFS=
printf '<%s>\n' $*
In einigen Muscheln (heutzutage meistens) sehen Sie
<a>
<b>
Und nicht <ab>
einmal "$*"
würde sich erweitern ab
. Diese Schalen trennen diese a
und b
Positionsparameter immer noch, und dies wurde in der neuesten Version des Standards als POSIX-Anforderung festgelegt.
Wenn du. .. getan hast:
set a b
IFS=
var="$*" # note that the behaviour for var=$* is unspecified
printf '<%s>\n' $var
Sie würden sehen, <ab>
dass die Information, dass a
und b
2 separate Argumente waren, verloren ging, wenn sie zugewiesen wurde $var
.
¹ Natürlich sind es nicht nur Leerzeichen, die Wörter abgrenzen. Es gibt auch spezielle Token in der Shell-Syntax, deren Liste vom Kontext abhängt. In den meisten Kontexten |
, ||
, &
, ;
, Newline <
, >
, >>
... abgrenzen Worte. Zum ksh93
Beispiel können Sie einen Befehl ohne Leerzeichen schreiben, wie:
while({([[(:)]])})&&((1||1))do(:);uname<&2|tee>(rev)file;done
IFS=:
undx="foo :bar"
, inargs $x
. Wie wäre die Reihenfolge hier? Zum Beispiel wird nach dem Tokenargs
und dem$x
Identifizieren des letzteren das Token erweitert und erneut markiert.args $x
ist es, als ob Sierun_simple_command("args", split($x))
in einer anderen Sprache geschrieben hätten (undrun_simple_command(glob("args"), glob(split($x)))
Globbing gilt auch). Während für die Bourne-Shell wäre es so gewesenrun_simple_command(glob(split("args")), glob(split($x)))
. Siehe auch: Sicherheitsauswirkungen des Vergessens, eine Variable in Bash / POSIX-Shells zu zitieren$* (which contains a::b) is split into a, the empty string and b.
Warum$*
ista::b
? Ich denke als nächstes: das$1
=a
,$2
=:b
und$*
verarbeitet dasa
ohne Änderungen, teilt dann das:b
in zwei Teile - der linke ist ein leerer String und der rechte istb
. Also bekommen wir{a}{}{b}
. Versuchen Sie esargs :b
. Sie erhalten auch eine leere Zeichenfolge -{}{b}
.args(){ echo '$1 = '"$1"; echo '$2 = '"$2"; printf '{%s}' $*; echo ""; } args :b; args a :b;
$*
in "a", "" und "b" aufgeteilt wird, weil es getrennt ist "a" und ": b" aufgeteilt in "" und "b" (wie in einigen Shells), oder weil wenn $ * zuerst in "a" verbunden ist :: b "und dann in" a "," "und" b "aufgeteilt (wie in einigen anderen Shells) führt ohnehin in allen Fällen zum gleichen Ergebnis, mit Ausnahme des leeren IFS- Falls.