2012-08-13 7 views
6

Ich kann dies in ksh, aber nicht in Bash arbeiten, die mich wirklich verrückt macht. Hoffentlich ist es etwas Offensichtliches, das ich übersehe.Bash Problem beim Zuweisen eines Array-Index in einer Schleife

Ich muss einen externen Befehl ausführen, bei dem jede Zeile der Ausgabe in einem Array-Index gespeichert wird.

Dieses vereinfachte Beispiel sieht so aus, als ob es das Array in der Schleife richtig setzt, aber nachdem die Schleife fertig ist, sind diese Array-Zuweisungen weg? Es ist, als ob die Schleife vollständig als äußere Hülle behandelt wird?

junk.txt

this is a 
test to see 
if this works ok 

testa.sh

#!/bin/bash 

declare -i i=0 
declare -a array 

echo "Simple Test:" 
array[0]="hello" 
echo "array[0] = ${array[0]}" 

echo -e "\nLoop through junk.txt:" 
cat junk.txt | while read line 
do 
    array[i]="$line" 
    echo "array[$i] = ${array[i]}" 
    let i++ 
done 

echo -e "\nResults:" 
echo "  array[0] = ${array[0]}" 
echo " Total in array = ${#array[*]}" 
echo "The whole array:" 
echo ${array[@]} 

Output

Simple Test: 
array[0] = hello 

Loop through junk.txt: 
array[0] = this is a 
array[1] = test to see 
array[2] = if this works ok 

Results: 
     array[0] = hello 
Total in array = 1 
The whole array: 
hello 

Während also in der Schleife, ordnen wir array [i] und das Echo es überprüft. Aber nach der Schleife bin ich wieder bei Array [0] mit "Hallo" ohne andere Elemente.

Gleiche Ergebnisse über Bash 3, 4 und verschiedenen Plattformen.

Antwort

7

Da sich Ihre while-Schleife in einer Pipeline befindet, sind alle Variablenzuweisungen im Schleifenkörper lokal für die Untershell, in der die Schleife ausgeführt wird. (Ich glaube, ksh den Befehl nicht in einer Subshell ausgeführt werden, weshalb Sie das Problem in bash haben.) Tun Sie dies statt:

while read line 
do 
    array[i]="$line" 
    echo "array[$i] = ${array[i]}" 
    let i++ 
done < junk.txt 

Selten, wenn überhaupt, haben Sie cat zu Rohr ein verwenden möchten einzelne Datei zu einem anderen Befehl; Verwenden Sie stattdessen die Eingabeumleitung.

UPDATE: da Sie von einem Befehl und nicht eine Datei, eine andere Option (falls vorhanden) ist Prozess Substitution ausführen müssen:

while read line; do 
... 
done < <(command args ...) 

Wenn Prozess Substitution nicht verfügbar ist, werden Sie auf die Ausgabe benötigen eine temporäre Datei und Weiterleitung der Eingabe aus dieser Datei.

Wenn Sie bash 4.2 oder höher verwenden, können Sie diese beiden Befehle vor Ihrer Schleife ausführen, und die ursprüngliche pipe-in-the-Schleife funktioniert, da die while-Schleife der letzte Befehl in der Pipeline ist.

set +m # Turn off job control; it's probably already off in a non-interactive script 
shopt -s lastpipe 
cat junk.txt | while read line; do ...; done 

UPDATE 2: Hier ist eine Schleife lose Lösung, basierend auf Kommentar des user1596414

array[0]=hello 
IFS=$'\n' array+=($(command)) 

Die Ausgabe des Befehls in Worte auf Zeilenumbrüche basieren ausschließlich geteilt wird (so dass jede Zeile ein separates Wort), und hängt das resultierende Array Zeile für Slot an das Original an. Dies ist sehr nützlich, wenn Sie nur die Schleife verwenden, um das Array zu erstellen. Es kann auch wahrscheinlich modifiziert werden, um eine kleine Menge von pro Zeile Verarbeitung, vage ähnlich einem Verständnis der Python-Liste zu empfangen.

+0

"Ich muss einen externen Befehl ausführen, bei dem jede Zeile der Ausgabe in einem Array-Index gespeichert wird." Die "Katze" war ein vereinfachtes Beispiel. Ich muss einen Befehl ausführen und es in die Schleife und eine Weiterleitung wie user1596414

+0

Aktualisiert mit ein paar Optionen. Der letzte (wenn deine Version von bash neu genug ist) ist wahrscheinlich der, den du willst. – chepner

+1

+1 eine temporäre Datei oder die bash 4.2 (oder später) Optionen funktionieren. Es gibt eine dritte Option, die IFS verwendet, um Leerstellen zu behandeln, und kann mit einer einfachen Array-Zuweisung kombiniert werden, wenn es auch nicht notwendig ist, die Ausgabe zu durchlaufen. – user1596414

Verwandte Themen