( jw013 hat bereits eine richtige Antwort gegeben , aber ich möchte auf einige weitere Probleme hinweisen.)
Die rechte Seite einer Pipeline wird in bash in einer eigenen Subshell ausgeführt (wie auch die meisten anderen Shells, mit Ausnahme von ATT ksh und zsh). Sie legen also die Umgebungsvariablen in der Subshell fest, die die Schleife ausführt, jedoch nicht im Haupt-Shell-Prozess.
Hier gibt es eine einfache Lösung, die die nutzlose Verwendung cat
durch eine Umleitung ersetzt:
while read …; do …; done <"$1"
Wenn Sie die Eingabe vorverarbeiten müssen, fügen Sie im Allgemeinen die Schleife und den Rest des Skripts (zumindest den Teil, der die geänderten Variablen benötigt) in einen Block ein.
grep '^foo_' "$1" | {
while read …; do …; done
do_something
}
Beachten Sie, dass while read line; do …
die Eingabezeilen im Allgemeinen nicht vollständig durchlaufen werden. Siehe Warum wird while IFS= read
so oft verwendet, anstatt IFS=; while read..
? für eine Erklärung. Die richtige Redewendung zum Durchlaufen von Eingabezeilen lautet
while IFS= read -r line; do …
Hier spielt das Entfernen von führenden und nachfolgenden Leerzeichen keine Rolle, da Ihre Beispieleingabe nicht angegeben werden sollte. Möglicherweise müssen Sie -r
jedoch eine Backslash-Erweiterung vermeiden. Es ist möglich, dass dies while read line
tatsächlich eine korrekte Art ist, Ihre Eingabe zu lesen (aber ich vermute nur, wenn die Variablenwerte keine Zeilenumbrüche enthalten). Es ist auch möglich, dass Ihr Eingabeformat mehrdeutig oder komplexer zu analysieren ist. Überprüfen Sie, was passiert, wenn einer der Variablenwerte ein Zeilenumbruchzeichen, ein doppeltes Anführungszeichen oder einen Backslash enthält.
Ein Punkt, an dem Sie die Eingabe definitiv entstellen, ist, wenn Sie den Wert extrahieren:
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
Zunächst müssen Sie doppelte Anführungszeichen um die Variablensubstitution verwenden : echo "${kv#*=}"
; Andernfalls führt die Shell eine Wortaufteilung und Dateinamengenerierung (dh Globbing) durch. Zweitens echo
ist dies keine zuverlässige Methode zum Drucken einer Zeichenfolge, da einige Zeichenfolgen, die mit a beginnen, -
als Optionen behandelt werden und einige Shells eine Backslash-Erweiterung für das Argument ausführen. Eine zuverlässige und tragbare Methode zum Drucken einer Zeichenfolge ist printf %s "${kv#*=}"
. Wenn sich der Wert über mehrere Zeilen erstreckt, wirkt das sed-Programm auf jede einzelne Zeile, was falsch ist. Dies kann behoben werden, aber es gibt eine einfachere Methode, nämlich die String-Manipulationsfunktionen der Shell zu verwenden : val=${kv#*=}; val=${val#\"}; val=${val%\"}
.
Unter der Annahme, dass Ihre Eingabe korrekt mit einer Ebene read
analysiert wurde, können Sie sie auf einfachere Weise analysieren und dabei die IFS
Einstellung zum Teilen jeder Zeile nutzen:
while read name value; do
value=${value#\"}; value=${value%\"}
export name="$value"
done <"$1"
key=${kv%%=*}
ist besser alskey=${kv%=*}
weil %% und ## sich von% und # unterscheiden, ob der entfernte Teil ist das kürzeste oder längste abnehmbare Teil