2012-02-02 19 views
12

Trong một số comment on another post, @JonathanLeffler đã tuyên bố rằng:Bash subshell/pipelines - phần nào đang thực hiện trong subshells?

{...} | somecommand được chạy trong một hệ vỏ con và không ảnh hưởng đến vỏ mẹ . Demo:

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

(với sản lượng PQR, ABC, PQR trên ba dòng)

và thực sự:

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

Tuy nhiên, man bash nói rằng { .. } làm không thực hiện trong một vỏ:

{ 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. 

Vậy điều gì đang xảy ra ở đây? man bash có sai không? Tôi biết rằng mỗi phần của một đường ống thực hiện trong một vỏ bọc con; nhưng tôi không thấy nó gây ra hành vi quan sát như thế nào. Ví dụ:

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

Edited thêm:

Một vài người đã đề nghị sử dụng echo $$ để chứng minh rằng điều được (hoặc không) các bộ phận của một subshell. Điều này hoàn toàn không hữu ích, vì $$ được mở rộng trong giai đoạn mở rộng tham số, điều này xảy ra lâu trước khi bất kỳ lệnh nào được thực thi.

Như một ví dụ:

[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$ 

Bạn có thể thấy rằng gọi thứ hai của ps xảy ra bên trong một subshell, với pid 7894; nhưng echo 2$$ vẫn cho thấy giá trị mà bash thay thế trong giai đoạn mở rộng biến, trước khi nó sinh ra các subshell

Đối với độ tương phản, và chứng minh rằng { .. } không không spawn một subshell:

[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 

Chỉ cần để chứng minh rằng @nos là chính xác, hãy thêm một đường dẫn vào phần trên:

[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 

Như dự kiến, vỏ sinh ra hai vỏ con, một cho mỗi bên của đường ống.

Trả lời

9

Mỗi bên của một đường ống trở thành một vỏ con ít nhất.

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

sẽ làm cho một subshell/quá trình, ít nhất { X=ABC; echo $X; }cat.

"Mỗi lệnh trong một đường ống được thực hiện dưới dạng một quá trình riêng biệt (tức là trong một vỏ bọc con)". , Từ man bash

Nếu bạn thay vì làm điều này

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

Bạn sẽ thấy sau đó echo $X lãm ABC.

Có các cách khác để thực thi lệnh trong các khung con, ví dụ: nếu bạn nền một tiểu ban: { X=SUB ; sleep 1; } &, nhóm đó sẽ chạy trong một vỏ cây con, trong khi chỉ { X=SUB ; sleep 1; } sẽ không hoạt động.

Nếu bạn muốn nhóm các lệnh luôn thực hiện trong một vỏ con, hãy sử dụng dấu ngoặc đơn, (X=ABC ; echo $X) thay vì dấu ngoặc nhọn.

+1

Tôi nghĩ rằng chúng tôi có một người chiến thắng. Nó không phải là '{..}' đang tạo ra subshell, đó là đường ống dẫn. Tôi thực tế đã ra ngay và nói điều đó ngay từ đầu. –

+2

Bạn cần một khoảng trắng sau '{', ít nhất là trong phiên bản 'bash' của tôi. Cấu trúc – krlmlr

+1

$ (cmd args) cũng tạo ra một subshell: 'echo $ (echo $ BASH_SUBSHELL)' –

1

Thật vậy, các dấu ngoặc ôm được thực hiện trong một vỏ mới, nhưng chỉ khi đường ống. Lệnh đầu tiên là với cat, thứ hai không:

[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 

Trong trường hợp này 6768 là PID của vỏ thiết bị đầu cuối, và 13159 là PID của subshell bắt đầu cho niềng răng.

Dường như {} được thực hiện trong một vỏ con nếu (và chỉ khi) được bơm.

+2

Đường ống tạo vỏ con, chứ không phải niềng răng. –

+1

Không, nó không phải là đường ống, đó là niềng răng trong kết nối với đường ống. Kiểm tra đầu ra của 'ps' so với' ps | cat' so với '{ps; } | cat'.. – krlmlr

+2

Niềng răng không bao giờ gọi một vỏ bọc! Chỉ có ống sẽ làm điều này: http://unix.stackexchange.com/questions/127334/bash-subshell-creation-with-curly-braces – slm

Các vấn đề liên quan