2011-04-22 58 views
8

編輯:管子的左側是子殼?

下面關於sed '[email protected]^@ @' <(f1)我的評論是不正確 雖然$BASH_SUBSHELL表明我們是在同一水平發射,變量在主腳本丟失。 基於戈登答案我測試了f1 > >(sed '[email protected]^@ @')而不是這似乎工作正常。但是,對於第一種形式,不應該BASH_SUBSHELL爲1而不是0?


考慮這個小測試

#!/bin/bash 
declare -i i=0 
function f1() 
{ 
    let i++ 
    echo "In f1, SUBSHELL: $BASH_SUBSHELL, i=$i" >&2 
} 

f1 
f1 | sed '[email protected]^@  @' 

echo "at end, i=$i" 

與下面的輸出:

In f1, SUBSHELL: 0, i=1 
In f1, SUBSHELL: 1, i=2 
at end, i=1 

(該sed的目的只是爲了有一個管的東西,不要指望它做任何事情,因爲f1輸出到stderr)

函數f1記錄當前的BASH_SUBSH ELL和我

我知道爲什麼在腳本的末尾,我們得到i=1的電流值,其因爲第二次調用是在一個子shell,我在殼層1的值丟失。

什麼我不知道的是,爲什麼管的左側在當前shell

雖然我想,我可以sed '[email protected]^@ @' <(f1) 我想避免這種情況知道爲什麼左側是未執行與主腳本不在同一級別

+0

我覺得shell允許在子shell中有管道的兩端 – sehe 2011-04-22 22:32:54

+0

快速谷歌發現這個:http://www.linuxprogrammingblog.com/pipe-in​​-bash-can-be-a-trap – 2011-04-22 22:37:28

+0

@布賴恩那篇文章沒有討論管道的左側...我已經知道這對管道右側的變量賦值是個壞消息 – nhed 2011-04-22 22:51:54

回答

12

bash man page:「流水線中的每個命令都作爲單獨的進程執行(即在子shell中)。」我猜想可以在當前shell中執行管道的一個組件(即第一個,也可以是最後一個,也可能是中間的一個),但它不會像這樣播放收藏夾:它們都在子殼體中執行全部 。如果您修改劇本是這樣的:

#!/bin/bash 
declare -i i=0 
function f1() 
{ 
    let i++ 
    echo "In f1, SUBSHELL: $BASH_SUBSHELL, i=$i" >&2 
} 

f1 
f1 | f1 | f1 

echo "at end, i=$i" 

它打印:

In f1, SUBSHELL: 0, i=1 
In f1, SUBSHELL: 1, i=2 
In f1, SUBSHELL: 1, i=2 
In f1, SUBSHELL: 1, i=2 
at end, i=1 

,因爲所有3調用F1的子shell中的管道運行。

+0

我想我的困惑來自管道和文件重定向的想法有點相同'f1 nhed 2011-04-22 23:14:18

+0

@nhed:我不會想到像輸出重定向的管道。管道是由I/O重定向串聯在一起的一系列命令,並且全部同時運行;由於shell不會執行多任務,因此它可以在主shell中運行其中的大部分任務,並且因爲它們基本相同,所以沒有理由選擇一個在主shell中運行,所以爲了公平,它們都是在子殼中運行。在bash中,你可以使用'< <()' and '>>()'將一些命令顯式地放到子shell中,允許一個命令在主shell中運行。 – 2011-04-23 04:42:55

+3

@nhed :(繼續)例如,強制管道中的第一個命令在主shell中運行,使用'cmd1 >>>(cmd2 | cmd3 | ...)''。要在主shell中運行cmd2,使用'cmd2 < <(cmd1) >>(cmd3 | ...)'等。 – 2011-04-23 04:45:53

-1

這是一個非常簡潔的例子,如果有人關心:

cd/&& cd /tmp/ | pwd ; pwd 
/
/

或者:

cd/&& cd /tmp/ | cd /var/ ; pwd 
/

是這個頁面說,這一切

http://linux.die.net/man/1/bash#管道中的每個命令都作爲執行單獨的過程(即在一個子殼中)。