Eine variable verändert sich innerhalb einer while-Schleife wird nicht gespeichert
In dem folgenden Programm, wenn ich die variable $foo
auf den Wert 1 innerhalb der ersten if
Aussage, es funktioniert in dem Sinne, dass Ihr Wert wird gespeichert nach der if-Anweisung. Allerdings, wenn ich die gleiche variable auf den Wert 2 innerhalb einer if
die in einem while
Aussage, es ist vergessen, nach der while
Schleife. Es verhält sich so wie ich über irgendeine Art von Kopie der variable $foo
innerhalb der while
loop und ich bin nur das veränderte, insbesondere kopieren. Hier ist eine komplette test-Programm:
#!/bin/bash
set -e
set -u
foo=0
bar="hello"
if [[ "$bar" == "hello" ]]
then
foo=1
echo "Setting \$foo to 1: $foo"
fi
echo "Variable \$foo after if statement: $foo"
lines="first line\nsecond line\nthird line"
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done
echo "Variable \$foo after while loop: $foo"
# Output:
# $ ./testbash.sh
# Setting $foo to 1: 1
# Variable $foo after if statement: 1
# Value of $foo in while loop body: 1
# Variable $foo updated to 2 inside if inside while loop
# Value of $foo in while loop body: 2
# Value of $foo in while loop body: 2
# Variable $foo after while loop: 1
# bash --version
# GNU bash, version 4.1.10(4)-release (i686-pc-cygwin)
Schlüssel Lesen Sie hier: ich Variablen in einer Schleife, die in einer pipeline. Warum verschwinden Sie, nachdem die Schleife beendet wird? Oder, warum kann ich nicht weiterleiten von Daten zu Lesen?.
Die shellcheck utility fängt diese (siehe github.com/koalaman/shellcheck/wiki/SC2030); Ausschneiden und einfügen der oben genannten code in shellcheck.net Probleme in diesem feedback für Zeile 19:
Die shellcheck utility fängt diese (siehe github.com/koalaman/shellcheck/wiki/SC2030); Ausschneiden und einfügen der oben genannten code in shellcheck.net Probleme in diesem feedback für Zeile 19:
SC2030: Modification of foo is local (to subshell caused by pipeline).
InformationsquelleAutor Eric Lilja | 2013-05-31
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den
while
Schleife ausgeführt wird, in einer subshell. So werden änderungen, die Sie tun, um die variable wird nicht verfügbar sein, wenn die subshell beendet.Stattdessen können Sie eine die - Zeichenkette zu re-schreiben die while-Schleife in der main-shell-Prozess; nur
echo -e $lines
läuft in einer subshell:Können Sie loszuwerden, die eher hässlich
echo
in der here-Zeichenfolge oben, durch den ausbau der backslash-Sequenzen sofort bei der Zuweisunglines
. Die$'...'
form zu zitieren, die verwendet werden können gibt es:<<< "$(echo -e "$lines")"
einfache<<< "$lines"
was ist, wenn die Quelle war, aus
tail -f
anstatt fester text?Sie können
while read -r line; do echo "LINE: $line"; done < <(tail -f file)
(natürlich die Schleife nicht beenden, wie es weiter warten für die Eingabe vontail
).InformationsquelleAutor P.P.
AKTUALISIERT#2
Erklärung ist im Blue Moons Antwort.
Alternative Lösungen:
Beseitigen
echo
Fügen Sie das echo innerhalb der hier-ist-das-Dokument
Laufen
echo
im hintergrund:Umleiten in eine Datei explizit verarbeiten (denken Sie an das Leerzeichen in
< <
!):Oder leite es einfach an die
stdin
:Und eine für
chepner
(Beseitigungecho
):Variable
$lines
umgewandelt werden können, um ein array ohne starten eine neue sub-shell. Die Charaktere\
undn
umgewandelt werden einige Zeichen (z.B. eine echte neue-Zeile-Zeichen) und die IFS (Internal Field Separator) variable split die Zeichenfolge in ein array von Elementen. Diese kann getan werden, wie:Ergebnis ist
lines
variable einzige Zweck scheint zu sein, zu fütternwhile
Schleife.Thx!!! Ich fügte hinzu, ein anderes, für Sie!
Es gibt noch eine andere Lösung gegeben hier:
for line in $(echo -e $lines); do ... done
Vielen Dank für Ihren Kommentar! Würde diese Lösung im Ergebnis 6 Zeilen mit einem einzigen Wort. OP ' s Anfrage war anders...
von Ihnen positiv bewertet werden. läuft echo in einer subshell hier drinnen-ist, war eine der wenigen Lösungen, die arbeitete in Esche
InformationsquelleAutor TrueY
Sind Sie der 742342nd Benutzer zu Fragen, dies bash-FAQ. Die Antwort beschreibt auch den Allgemeinen Fall der Variablen in subshells erstellt von pipes:
InformationsquelleAutor Jens
Hmmm... ich würde fast schwören, dass das funktioniert hat, die für die ursprüngliche Bourne-shell, aber don ' T haben Zugriff auf eine ausgeführte Kopie gerade jetzt zu überprüfen.
Es ist jedoch eine sehr triviale Lösung für das problem.
Ändern Sie die erste Zeile des Skripts aus:
zu
Et voila! Ein Lesen am Ende einer pipeline funktioniert gut, vorausgesetzt, Sie haben die Korn-shell installiert.
InformationsquelleAutor Jonathan Quist
Dies ist eine interessante Frage, und berühren Sie ein sehr grundlegendes Konzept in der Bourne-shell und subshell. Hier habe ich eine Lösung bereitzustellen, die sich von den vorherigen Lösungen, indem Sie eine Art der Filterung. Ich werde ein Beispiel geben, dass kann nützlich sein im wirklichen Leben. Dies ist ein fragment zum überprüfen der heruntergeladenen Dateien entsprechen zu wissen Prüfsummen. Die Datei-Prüfsumme wie folgt Aussehen (Mit nur 3 Zeilen):
Dem shell-script:
Den Eltern und subshell kommunizieren, durch den echo-Befehl. Sie können wählen Sie eine einfach zu parsende text für die Eltern-shell. Diese Methode wird nicht brechen Ihre normale Art zu denken, nur, dass Sie zu tun haben, einige post-processing. Sie können mit grep, sed, awk, und mehr zu tun.
InformationsquelleAutor Kemin Zhou
Wie wäre es mit einer sehr einfachen Methode
Meinst du den original-code ist angenehm zu Lesen? (Habe ich einfach gefolgt :p)
InformationsquelleAutor Marcin