Ich habe eine Variable, die mehrzeilige Ausgabe eines Befehls enthält. Was ist die effizienteste Methode, um die Ausgabe zeilenweise aus der Variablen zu lesen?
Zum Beispiel:
jobs="$(jobs)"
if [ "$jobs" ]; then
# read lines from $jobs
fi
Sie können eine while-Schleife mit Prozessersetzung verwenden:
while read -r line
do
echo "$line"
done < <(jobs)
Eine optimale Methode zum Lesen einer mehrzeiligen Variablen besteht darin, eine leere IFS
Variable printf
festzulegen und die Variable mit einem nachgestellten Zeilenumbruch zu versehen:
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
do
echo "$line"
done < <(printf '%s\n' "$var")
Hinweis: Gemäß Shellcheck sc2031 ist die Verwendung von Prozesssubition einer Pipe vorzuziehen, um das [subtile] Erstellen einer Subshell zu vermeiden.
Beachten Sie außerdem, dass die Benennung der Variablen jobs
zu Verwirrung führen kann, da dies auch der Name eines allgemeinen Shell-Befehls ist.
while IFS= read
read -r
echo
zuprintf %s
, so dass Ihr Skript funktionieren würde, auch bei nicht zahm Eingang./tmp
, da es darauf ankommt , dass eine temporäre Arbeitsdatei erstellt werden kann. Sollten Sie sich jemals in einem eingeschränkten System befinden/tmp
, das schreibgeschützt ist (und von Ihnen nicht geändert werden kann), werden Sie sich über die Möglichkeit freuen, eine alternative Lösung zu verwenden, zprintf
. B. mit der Pipe.printf "%s\n" "$var" | while IFS= read -r line
So verarbeiten Sie die Ausgabe eines Befehls zeilenweise ( Erläuterung ):
Wenn Sie die Daten bereits in einer Variablen haben:
printf %s "$foo"
ist fast identisch mitecho "$foo"
, gibt jedoch$foo
buchstäblich aus, wobei dies als Option für den Echo-Befehlecho "$foo"
interpretiert werden kann,$foo
wenn er mit einem beginnt-
, und möglicherweise die Backslash-Sequenzen$foo
in einigen Shells erweitert.Beachten Sie, dass in einigen Shells (ash, bash, pdksh, aber nicht ksh oder zsh) die rechte Seite einer Pipeline in einem separaten Prozess ausgeführt wird, sodass alle in der Schleife festgelegten Variablen verloren gehen. Das folgende Skript für die Zeilenzählung gibt beispielsweise 0 in diesen Shells aus:
Eine Problemumgehung besteht darin, den Rest des Skripts (oder zumindest den Teil, der den Wert
$n
aus der Schleife benötigt) in eine Befehlsliste einzufügen:Wenn das Eingreifen in die nicht leeren Zeilen gut genug ist und die Eingabe nicht sehr umfangreich ist, können Sie die Wortteilung verwenden:
Erläuterung:
IFS
Wenn Sie eine einzelne Zeile als Zeilenumbruch festlegen, wird das Wort nur in Zeilenumbrüchen aufgeteilt (im Gegensatz zu Leerzeichen in der Standardeinstellung).set -f
Deaktiviert das Globbing (dh die Platzhaltererweiterung), das andernfalls bei einer Befehlsersetzung$(jobs)
oder einer Variablenersetzung auftreten würde$foo
. Diefor
Schleife wirkt auf alle Teile von$(jobs)
, also alle nicht leeren Zeilen in der Befehlsausgabe. Stellen Sie abschließend die Globbing-IFS
Einstellungen wieder her.quelle
local IFS=something
. Der Wert für den globalen Bereich wird nicht beeinflusst. IIRCunset IFS
bringt Sie nicht auf die Standardeinstellungen zurück (und funktioniert auf keinen Fall, wenn dies vorher nicht die Standardeinstellungen war).Problem: Wenn Sie eine while-Schleife verwenden, wird diese in der Subshell ausgeführt und alle Variablen gehen verloren. Lösung: Verwenden Sie für Schleife
quelle
while read
Schleife in Bash bedeutet, dass sich die While-Schleife in einer Subshell befindet, sodass Variablen nicht global sind.while read;do ;done <<< "$var"
macht den Schleifenkörper nicht zu einer Unterschale. (Letzte Bash hat eine Option, um den Körper einercmd | while
Schleife nicht in eine Unterschale zu setzen, wie ksh es immer getan hat.)Verwenden Sie in neueren Bash-Versionen
mapfile
oderreadarray
, um die Befehlsausgabe effizient in Arrays zu lesenHaftungsausschluss: Ein schreckliches Beispiel, aber Sie können sich durchaus einen besseren Befehl einfallen lassen als Sie
quelle
readarray
eine Funktion ein und rufen Sie die Funktion einige Male auf.Verweise:
while
IFS
read
quelle
-r
ist auch eine gute Idee; Es verhindert, dass\` interpretation... (it is in your links, but its probably worth mentioning, just to round out your
IFS = `(was wichtig ist, um den Verlust von Leerzeichen zu verhindern)Mit <<< können Sie einfach aus der Variablen lesen, die die durch Zeilenumbrüche getrennten Daten enthält:
quelle