Warum druckt dieses Shell-Skript Eingaben zweimal?
Ich habe erwartet, dass das Skript die Eingaben nach 5 ignoriert.
Skript:
#! /bin/bash
echo "Enter 5 words : "
read a b c d e
printf "> %s %s %s %s %s <" $a $b $c $d $e
Ausgabe:
user@linux:~$ pico ifs2.sh
user@linux:~$ ./ifs2.sh
Enter 5 words :
1 2 3 4 5
> 1 2 3 4 5 <user@linux:~$ ./ifs2.sh
Enter 5 words :
1 2 3 4 5 6
> 1 2 3 4 5 <> 6 <user@linux:~$ ./ifs2.sh
Enter 5 words :
1 2 3 4 5 6 7 8 9 0
> 1 2 3 4 5 <> 6 7 8 9 0 <user@linux:~$
Das folgende Skript funktioniert unabhängig davon, was auf $ IFS eingestellt ist. Warum?
#! /bin/bash
old="$IFS"
IFS=":"
echo "IFS = $IFS"
echo "Enter 5 words : "
read a b c d e
printf "> %s %s %s %s %s <" $a $b $c $d $e
IFS="$old"
Ausgabe:
user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words :
1 2 3 4 5
> 1 2 3 4 5 <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words :
1 2 3 4 5
> 1 2 3 4 5 <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words :
1:2:3:4:5
> 1 2 3 4 5 <user@linux:~$
shell-script
mikeserv
quelle
quelle
printf
jederzeit mit dem\c
Escape, das einem%b
Formatbezeichner zugeordnet ist. Wie:printf %s%\ d%b thing 3 "${var+\cquit printing if set}\nelse do a newline" and 0 keep\ going.
Antworten:
Sie haben drei Probleme:
read
, wird an alle die übrigen Felder auf der Linie mit Begrenzungszeichen, gebunden, wenn es weniger Variablennamen als Felder in der Eingabe, die letzte var sind. Das heißt, das$e
kommt5 6
in Ihr erstes unerwartetes Beispiel.$a
..$e
unquoted sind, durchlaufen ihre Werte Feldaufspaltung . Wenn$e
"5 6
" gilt , wird der Befehl in zwei Argumente erweitert .printf
verbraucht alle seine Argumente und verwendet so viele Argumente gleichzeitig, wie es%
Substitutionen gibt, wiederholt. Dies ist in der Dokumentation wie folgt vergraben :Mit anderen Worten, wenn nicht verwendete Argumente vorhanden sind, wird von vorne begonnen und auch von Anfang an verarbeitet, einschließlich der gesamten Formatzeichenfolge. Dies ist nützlich, wenn Sie ein gesamtes Array formatieren möchten, z. B.:
Ihr
printf
Befehl erhält jeweils ein Argument von$a
..$d
, und dann bleiben jedoch viele übrig$e
. Wenn$e
"5 6
" ist,printf
hat zwei Runden, die zweite wird gerade6
formatiert. Wenn es ist5 6 7 8 9 10
, hat es die volle Auswahl an Ersetzungen für den zweiten Druck.Sie können all dies vermeiden, indem Sie ein zusätzliches Dummy-Feld hinzufügen
read
und Ihre Parametersubstitutionen angeben (was immer eine gute Idee ist):Dies wird geben:
dummy
Ruft alle zusätzlichen Felder ab undprintf
nur die fünf erwarteten Argumente.Ihre zweite bearbeitete Frage hat eine ähnliche Antwort: Erhält nur
a
dann einen Wert, wennIFS
kein Leerzeichen vorhanden ist. Das heißt$b
..$e
auf nichts erweitern, alsoprintf
nur ein einziges Argument bekommen. Ihre Leerzeichen aus der Formatzeichenfolge werden gedruckt, ohne dass dazwischen etwas ersetzt wird ("als ob ein Nullzeichenfolgenargument angegeben wäre").quelle
a
hat den Wert1 2 3 4 5
als einzelne Zeichenfolge und wird auf einmal ersetzt.wird gedruckt
druckt
printf
Frisst alle Argumente auf, um die Formatzeichenfolge zu erfüllen, und wiederholt sie dann, bis alle Argumente verarbeitet sind.Das zweite Skript funktioniert, weil immer nur
$a
zugewiesen wird und der Befehl daher nicht in zusätzliche Iterationen überläuft (es gibt immer nur eine Iteration).Dieses Verhalten ist im folgenden Text dokumentiert
help printf
:und wird von http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html beauftragt
quelle