Ich schreibe ein Bash-Shell-Skript, um bzip2
zu verwenden, um alle .bsp
-Dateien in einem Verzeichnis zu zippen. In diesem Skript habe ich mehrere Variablen zum Zählen von Summen (Dateien, erfolgreiche Reißverschlüsse, erfolgreiche Integritäts-Scans), jedoch scheint mir ein Problem aufgetreten zu sein.
Wenn find $loc -name "*.bsp"
keine Dateien mehr enthält, um die while read
und while read
zu verlassen, wird $filcount
, $zipcount
und $scacount
(alle innerhalb von initiate ()
geändert (erhöht)) , bzip ()
(wird während initiate ()
aufgerufen) oder bzipint ()
(was auch in initiate ()
aufgerufen wird).
Um zu testen, ob es etwas mit Variablen zu tun hat, die sich in initiate ()
oder anderen Funktionen ändern, habe ich echo $valid
verwendet, das außerhalb von initiate ()
definiert wurde (wie $filcount
, $zipcount
usw.), wird aber nicht von einer anderen Funktion in initiate ()
oder innerhalb initiate ()
selbst geändert.
Interessanterweise wird $valid
nicht auf 0 zurückgesetzt, wie die anderen Variablen innerhalb von initiate.
Kann mir jemand sagen, warum meine Variablen auf magische Weise zurückgesetzt werden, wenn das Lesen beendet wird?
Ich bin gestern auf dieses Problem gestoßen.
Das Problem ist, dass du find $loc -name "*.bsp" | while read
machst. Da es sich um eine Pipe handelt, kann die while read
-Schleife nicht im selben Bash-Prozess wie der Rest des Skripts ausgeführt werden. Bash muss einen Subprozess erzeugen, damit er das stdout von find
mit der stdin der while
Schleife verbinden kann.
Das ist alles sehr schlau, aber es bedeutet, dass alle Variablen, die in der Schleife gesetzt sind, nach der Schleife nicht mehr gesehen werden können, was den ganzen Zweck der while
-Schleife, die ich geschrieben habe, total untergraben hat.
Sie können entweder versuchen, die Eingabe ohne eine Pipe in die Schleife einzufügen, oder Sie erhalten die Ausgabe aus der Schleife ohne Verwendung von Variablen. Ich endete mit einer entsetzlichen Abscheulichkeit, die sowohl das Schreiben in eine temporäre Datei als auch das Umschließen der gesamten Schleife in $(...)
beinhaltete:
Was mich dazu gebracht hat, all die Dinge wiederzugeben, die aus der Schleife stammen. Ich habe wahrscheinlich die Syntax dieses Beispiels durcheinander gebracht; Ich habe den Code, den ich im Moment geschrieben habe, nicht im Griff.
Um Optionen für zusammenzufassen, indem Sie read
am Ende von [dem konzeptionellen Gegenstück zu] einer Pipeline in POSIX-ähnlichen Shells verwenden:
Um es kurz zu machen: In bash standardmäßig und in streng POSIX-konformen Shells werden alle Befehle in einer Pipeline in einer subshell ausgeführt, also Variablen, die sie erstellen oder ändern ist für die aktuelle Shell nicht sichtbar (wird nach dem Ende der Pipeline nicht mehr existieren).
Die folgende deckt bash
, ksh
, zsh
und sh
([meist] POSIX-features-only-Shells wie dash
) ab und zeigt an Möglichkeiten, die Erstellung einer Subshell zu vermeiden, um die von read
erstellten / modifizierten Variablen zu erhalten.
Wenn keine Mindestversionsnummer angegeben wird, wird davon ausgegangen, dass sogar "ziemlich alte" Versionen dies unterstützen (die betreffenden Funktionen gibt es schon lange, aber ich weiß nicht genau, wann sie eingeführt wurden.
Beachten Sie, dass Sie als [POSIX-kompatible] Alternative zu den Lösungen immer die Ausgabe eines Befehls in einer [temporären] Datei erfassen und dann an read
als < file
füttern können vermeidet Subshells.
ksh
und zsh
: KEINE Problemumgehung / Konfigurationsänderung erforderlich: Das read
builtin wird standardmäßig in der aktuellen Shell ausgeführt, wenn es als letzter -Befehl in der Pipeline verwendet wird.
Scheinbar ksh
und zsh
standardmäßig führen any Befehl in der letzten Stufe einer Pipeline im aktuellen Schale.
Beobachtet in ksh 93u+
und zsh 5.0.5
.
Wenn Sie genau wissen, in welcher Version dieses Feature eingeführt wurde, lassen Sie es mich wissen.
bash 4.2+
: Verwenden Sie die lastpipe
Shell-Option In der Bash-Version 4.2 oder höher bewirkt das Aktivieren der Shell-Option lastpipe
, dass das letzte Pipeline-Segment in der aktuellen -Shell ausgeführt wird. Dadurch können Variablen für die aktuelle Shell sichtbar gemacht werden.
bash
, ksh
, zsh
: Verwenden Sie die Prozesssubstitution
Eine Prozesssubstitution ist eine Möglichkeit, die Ausgabe eines Befehls wie eine temporäre Datei zu gestalten.
%Vor%bash
, ksh
, zsh
: Verwenden Sie eine Hier-Zeichenfolge mit einem < a href="http://mywiki.wooled.org/CommandSubstitution"> Befehlsersetzung
Beachten Sie, dass Sie die Befehlsersetzung doppelt angeben müssen, um ihre Ausgabe vor Shell-Erweiterungen zu schützen .
sh
): Verwenden Sie ein Here-Dokument mit einem Befehlsersetzung
Beachten Sie, dass Sie in diesem Fall das Endtrennzeichen - EOF
- ganz am Anfang der Zeile platzieren müssen und dass keine Zeichen folgen müssen.
Tags und Links bash shell while-loop subshell