2015-01-28 7 views
5

in bash bekommen, ich liebe es, aber es scheint, gibt es viele Feinheiten, die einen großen Unterschied in der Funktionalität am Ende machen, und so weiter, jedenfalls hier meine Frage:Bash Rohrbefehlsausgabe in Summe Schleife

I weiß, das funktioniert:

total=0 
for i in $(grep number some.txt | cut -d " " -f 1); do 
    ((total+=i)) 
done 

Aber warum nicht tut dies ?:

grep number some.txt | cut -d " " -f 1 | while read i; do ((total+=i)); done 

some.txt:

1 number 
2 number 
50 number 

Sowohl die for- als auch die while-Schleife empfangen 1, 2 und 50 getrennt, aber die for-Schleife zeigt die Gesamtvariable am Ende auf 53, während sie im while-Schleifencode nur in Null bleibt. Ich weiß, dass es ein grundlegendes Wissen gibt, das mir hier fehlt, bitte hilf mir.

ich auch die Unterschiede nicht bekommen, zum Beispiel in Rohrleitungen, Wenn ich

grep number some.txt | cut -d " " -f 1 | while read i; echo "-> $i"; done 

laufen bekomme ich die erwartete Ausgabe

-> 1 
-> 2 
-> 50 

Aber wenn wie so laufen

while read i; echo "-> $i"; done <<< $(grep number some.txt | cut -d " " -f 1) 

dann ändert sich der Ausgang zu

-> 1 2 50 

Dies scheint mir seltsam, da grep das Ergebnis in separaten Zeilen ausgibt. Als ob dies nicht mehrdeutig, wenn ich eine Datei mit nur Zahlen hatte 1 2 3 in getrennten Linien, und ich lief

while read i; echo "-> $i"; done < someother.txt 

Dann würde der Ausgang durch das Echo in verschiedenen Zeilen gedruckt werden, wie in dem erwarteten vorheriges Beispiel. Ich weiß < ist für Dateien und < < < für Befehlsausgaben, aber warum existiert diese Linie Unterschied?

Wie auch immer, ich hoffte, dass jemand etwas Licht in die Sache bringen könnte, danke für Ihre Zeit!

+0

Als ein einfaches Beispiel für das Problem in der zweiten Frage versuchen: 'a = $ 'foo \ nbar'; Echo $ a; echo ===; echo "$ a; echo ===; cat <<< $ a; echo ===; cat <<<" $ a "'. –

+0

Sie können auch die Summe der ersten Spalte mit awk berechnen: 'awk '{a + = $ 1} END {print a} 'some.txt' –

Antwort

6
grep number some.txt | cut -d " " -f 1 | while read i; do ((total+=i)); done 

Jeder Befehl in einer Pipeline wird in einer Subshell ausgeführt. Das bedeutet, wenn Sie die while read Schleife in eine Pipeline setzen, gehen alle Variablenzuweisungen verloren.

See: BashFAQ 024 - "I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?"

while read i; echo "-> $i"; done <<< "$(grep number some.txt | cut -d " " -f 1)" 

Um grep ‚s Zeilenumbrüche zu erhalten, fügen Sie doppelte Anführungszeichen. Ansonsten unterliegt das Ergebnis von $(...) der Wortaufspaltung, die alle Leerräume in einzelne Leerzeichen zusammenfasst.

+2

Die andere Alternative ist 'set + m; shopt -s lastpipe', aber das ist wirklich matschig das Wasser –

+0

Nun, das macht die Dinge klar! Danke! – acib708