2014-10-20 110 views
2

我是學習bash和我在互聯網上找到的教程,說這些是相同的:在「while read -r line; do ...; done <file`和`cat file | while IFS = read -r line; do ...; done`之間bash之間有任何區別嗎?

while read -r line; 
do 
    ... 
done < file 

$ cat file | while IFS= read -r line; 
do 
    ... 
done 

是否有在這兩個循環的任何細微的差別是它們真的一樣

+2

我的建議:不要分析'cat'命令的輸出。 – 2014-10-20 17:41:10

+0

爲了擴大chepner已經觸及的內容:一般來說'cat foo | bar「而不是'bar 2014-10-20 18:17:37

+0

兩個循環都應該有'IFS ='? – 2014-10-20 18:53:03

回答

8

最大的區別是,在流水線,while循環在子shell中執行,因此如果更改while正文中任何變量的值,那麼在管道完成後這些變量將丟失。

$ foo=5 
$ cat file | while IFS= read -r line; do 
> foo=$line # assume $line is not 5 
> done 
$ echo $foo 
5 
$ while IFS= read -r line; do 
> foo=$line 
> done < file # Assume one line with the word foo 
$ echo $foo 
foo 

bash 4.2,這可以通過使用lastpipe選項,它允許在一管道中的最後一個命令在當前外殼,而不是子shell被執行來減輕。

除此之外,使用輸入重定向的版本更高效,因爲它不需要額外的進程啓動。

+0

很好的答案!當我只提到「無用的貓」時,我經常忘記這個變量範圍的東西:) – hek2mgl 2014-10-20 17:46:46

+0

但他們都有while循環? – bodacydo 2014-10-20 17:52:56

+0

對不起,我不清楚哪個結構需要一個子殼;編輯。 – chepner 2014-10-20 18:02:29

1

除了chepner關於subshel​​l的觀察,其中一個循環使用IFS=而另一個不使用。

read使用此變量分割單詞。使用一個變量時,會影響前導和尾隨空格。

隨着IFS=,它的保存:

$ IFS= read -r line <<< " test " 
$ printf "<%s>\n" "$line" 
< test > 

,否則就是剝奪:

$ read -r line <<< " test " 
$ printf "<%s>\n" "$line" 
<test> 

你可以想象第一個非IFS=環路會有多大的破壞沉船上如一個Python文件。