Bash beim Lesen Zurücksetzen von Variablenwerten - Verwendung des in einer Pipeline eingebauten Read

8
%Vor%

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?

    
mklement0 05.09.2011, 23:13
quelle

3 Antworten

7

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:

%Vor%

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.

    
Ben 05.09.2011, 23:28
quelle
10

wenn Sie bash

verwenden %Vor%     
ghostdog74 06.09.2011 02:45
quelle
7

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.

%Vor%

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.

%Vor%

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

%Vor%

Beachten Sie, dass Sie die Befehlsersetzung doppelt angeben müssen, um ihre Ausgabe vor Shell-Erweiterungen zu schützen .

POSIX-konforme Lösung ( sh ): Verwenden Sie ein Here-Dokument mit einem Befehlsersetzung

%Vor%

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.

    
mklement0 07.03.2015 17:31
quelle

Tags und Links