2012-02-02 60 views
12

comment on another post,@JonathanLeffler指出:Bash子殼/管道 - 哪些部件在子殼中執行?

{...} |有些命令是在子shell中運行的,並不會影響父shell的 。演示:

X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X

(帶輸出PQR,ABC,PQR三線)

確實:

[email protected]:tmp$X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X 
PQR 
ABC 
PQR 

然而,man bash{ .. }做不在子shell中執行:

{ list; } 
      list is simply executed in the current shell environment. list must be 
      terminated with a newline or semicolon. This is known as a group command. 

那麼是什麼回事?是man bash錯?我知道管道的每個部分都在子shell中執行;但我不明白這是怎麼導致觀察到的行爲。例如:

[email protected]:tmp$X=PQR; echo $X | sed; X=ABC; echo $X | sed; echo $X 
PQR 
ABC 
ABC 

編輯補充:

有幾個人使用echo $$表明事情(或者不是)一個子shell的部分建議。這並沒有什麼用處,因爲$$在參數展開階段得到擴展,在執行任何命令之前就已經發生了。

作爲一個例子:

[email protected]:tmp$echo 1$$; ps; (echo 2$$; ps); echo 3$$; ps 
11194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.22 -bash 
21194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.22 -bash 
7894 ttys000 0:00.00 -bash 
31194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.22 -bash 
[email protected]:tmp$ 

可以看到的ps第二次調用發生子外殼的內部,具有pid 7894;但echo 2$$仍然顯示的bash取代在可變膨脹階段,它產生了子外殼

對於對比度之前的值,並表明{ .. }確實產卵子shell:

[email protected]:tmp$echo 1$$; ps; { echo 2$$; ps; }; echo 3$$; ps 
11194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.22 -bash 
21194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.22 -bash 
31194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.23 -bash 

只是爲了證明@nos是正確的,管道添加到上面:

[email protected]:tmp$echo 1$$; ps; { echo 2$$; ps; } | sed ; echo 3$$; ps 
11194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.25 -bash 
21194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.25 -bash 
7945 ttys000 0:00.00 -bash 
7946 ttys000 0:00.00 sed 
31194 
    PID TTY   TIME CMD 
1194 ttys000 0:00.25 -bash 

正如預期的那樣,殼產卵2子shell,一個用於管道的每一側上。

回答

9

管道的每一側至少成爲一個子殼。

X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X

將使子shell /進程,至少{ X=ABC; echo $X; }cat

「流水線中的每個命令都作爲一個單獨的進程執行(即在一個子shell中)」。 ,從人bash的

如果不是這樣做

X=PQR; echo $X; { X=ABC; echo $X; } ; echo | cat; echo $X

你會看到事後說echo $X顯示ABC。

還有其他的方法可以在子殼體中執行命令,例如,如果您使用子命令:{ X=SUB ; sleep 1; } &,那麼該組將運行在一個子shell中,而只有{ X=SUB ; sleep 1; }不會。

如果您想對始終在子shell中執行的命令進行分組,請使用圓括號(X=ABC ; echo $X)而不是大括號。

+1

我認爲我們有一個贏家。這不是創建子shell的'{..}',它是管道。我實際上剛剛出來並在開始的時候說過。 – 2012-02-02 09:22:04

+2

在'{'之後,至少在我的'bash'版本中需要一個空格。 – krlmlr 2012-02-02 13:02:28

+1

$(cmd args)構造也創建一個子shell:'echo $(echo $ BASH_SUBSHELL)' – 2014-02-07 15:46:04

1

實際上,大括號在新的子shell中執行,但只有在管道中執行。第一個命令是與cat,第二無:

[email protected]:~$ ps; X=PQR; echo $X; { ps; X=ABC; echo $X; } | cat; ps; echo $X 
    PID TTY   TIME CMD 
6768 pts/7 00:00:00 bash 
13158 pts/7 00:00:00 ps 
PQR 
    PID TTY   TIME CMD 
6768 pts/7 00:00:00 bash 
13159 pts/7 00:00:00 bash 
13160 pts/7 00:00:00 cat 
13161 pts/7 00:00:00 ps 
ABC 
    PID TTY   TIME CMD 
6768 pts/7 00:00:00 bash 
13162 pts/7 00:00:00 ps 
PQR 
[email protected]:~$ ps; X=PQR; echo $X; { ps; X=ABC; echo $X; }; ps; echo $X 
    PID TTY   TIME CMD 
6768 pts/7 00:00:00 bash 
13239 pts/7 00:00:00 ps 
PQR 
    PID TTY   TIME CMD 
6768 pts/7 00:00:00 bash 
13240 pts/7 00:00:00 ps 
ABC 
    PID TTY   TIME CMD 
6768 pts/7 00:00:00 bash 
13245 pts/7 00:00:00 ps 
ABC 

在這種情況下6768是終端外殼的PID,和13159是子外殼的PID開始爲大括號。

似乎{}在一個子shell,如果(且僅當)管道執行。

+2

管道創建子殼,而不是大括號。 – 2012-02-02 09:40:01

+1

不,它不是管道,它是與管道相連的支架。檢查'ps'與'ps |的輸出貓'與'{ps; } | cat'。。 – krlmlr 2012-02-02 12:59:48

+2

大括號永遠不會調用子shell!只有管​​道會這樣做:http://unix.stackexchange.com/questions/127334/bash-subshel​​l-creation-with-curly-braces – slm 2014-05-03 04:28:24