$ () Là một nhánh con?


Câu trả lời:


75

$(…)là một định nghĩa con theo định nghĩa: nó là một bản sao của trạng thái thời gian chạy shell và các thay đổi đối với trạng thái được tạo trong lớp con không có tác động đến cha mẹ. Một subshell thường được thực hiện bởi forking một quá trình mới (nhưng một số vỏ có thể tối ưu hóa này trong một số trường hợp).

Nó không phải là một nhánh con mà bạn có thể lấy các giá trị biến từ đó. Nếu các thay đổi đối với các biến có tác động đến cha mẹ, thì đó sẽ không phải là một nhánh con. Đó là một mạng con có đầu ra mà cha mẹ có thể truy xuất. Subshell được tạo bởi $(…)có đầu ra tiêu chuẩn của nó được đặt thành một ống và cha mẹ đọc từ ống đó và thu thập đầu ra.

Có một số cấu trúc khác tạo ra một subshell. Tôi nghĩ rằng đây là danh sách đầy đủ cho bash:

  • Subshell cho nhóm : ( … )không làm gì ngoài việc tạo một subshell và chờ cho nó kết thúc). Tương phản với { … }các nhóm lệnh hoàn toàn cho mục đích cú pháp và không tạo ra một nhánh con.
  • Bối cảnh : … &tạo một lớp con và không chờ nó kết thúc.
  • Đường ống : … | …tạo ra hai khung con, một cho phía bên trái và một cho phía bên phải và chờ cho cả hai kết thúc. Vỏ tạo ra một đường ống và kết nối đầu ra tiêu chuẩn bên tay trái với đầu ghi của đường ống và đầu vào tiêu chuẩn bên tay phải với đầu đọc. Trong một số shell (ksh88, ksh93, zsh, bash với lastpipetùy chọn được thiết lập và hiệu quả), phía bên phải chạy trong shell ban đầu, do đó, cấu trúc đường ống chỉ tạo ra một lớp con.
  • Thay thế lệnh : $(…)(cũng được đánh vần `…`) tạo ra một khung con với đầu ra tiêu chuẩn của nó được đặt thành một đường ống, thu thập đầu ra trong cha mẹ và mở rộng ra đầu ra đó, trừ đi các dòng mới. (Và đầu ra có thể tiếp tục bị chia tách và tạo thành khối, nhưng đó là một câu chuyện khác.)
  • Quá trình thay thế : <(…)tạo ra một lớp con với đầu ra tiêu chuẩn của nó được đặt thành một đường ống và mở rộng thành tên của đường ống. Phụ huynh (hoặc một số quy trình khác) có thể mở đường ống để liên lạc với mạng con. >(…)làm như vậy nhưng với đường ống trên đầu vào tiêu chuẩn.
  • Coprocess : coproc …tạo một subshell và không chờ nó kết thúc. Mỗi đầu vào và đầu ra tiêu chuẩn của subshell được đặt thành một ống với cha mẹ được kết nối với đầu kia của mỗi ống.

¹ Trái ngược để chạy một vỏ riêng biệt .


Bạn cũng có thể bao gồm ${...}trong câu trả lời?
dùng1717828

3
@ user1717828 Gì? Tại sao? Mở rộng biến từ xa có liên quan gì đến câu hỏi này? Tôi sẽ không bao gồm toàn bộ hướng dẫn sử dụng vỏ trong câu trả lời của tôi.
Gilles 'SO- ngừng trở nên xấu xa'

1
Mở rộng biến từ xa có liên quan gì đến câu hỏi này? Tôi không biết, đó là lý do tại sao tôi hỏi :-) Vì vậy, tôi đoán thay thế niềng răng xoăn không giống như thay thế dấu ngoặc đơn.
dùng1717828

@ user1717828: mở rộng biến không liên quan đến subshells; đó là một cơ chế riêng biệt hoàn toàn và đáng để đọc nếu bạn mới bắt đầu!
0xdd

1
@EnricoMariaDeAngelis Đó không phải là cách duy nhất, mà là cách tự nhiên nhất. Một cách khác là command | { read line; … }(tùy thuộc vào vỏ, linecó thể hoặc không thể vẫn còn sau đường ống). Tất cả các cách liên quan đến một lớp con vì lệnh tạo đầu ra phải chạy độc lập với trình bao đọc đầu vào. Nếu lệnh hoàn toàn bên trong shell (chỉ có cấu trúc và cấu trúc shell, không có lệnh bên ngoài), shell có thể không tạo ra một quy trình con, nhưng đó chỉ là một tối ưu hóa, nó vẫn tạo ra một lớp con.
Gilles 'SO- ngừng trở nên xấu xa'

20

Từ trang man bash (1) trong phiên bản bash 4.4, phần "MỞ RỘNG", tiểu mục "Thay thế lệnh":

Bash thực hiện việc mở rộng bằng cách thực thi commandtrong môi trường lớp con [...]



1
Thật thú vị, trong CentOS 7, bashtrang này không đề cập đến bất kỳ phân nhóm nào: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.Tôi tự hỏi liệu đây có phải là một thiếu sót có chủ ý hay không.
dr01

6
@ dr01 Ngược lại, bash 4.4 đã thay đổi cách diễn đạt của câu đó để bao gồm từ "subshell". Đó là một sự làm rõ: hướng dẫn đã đề cập rõ ràng rằng các cấu trúc khác là các lớp con, nhưng cho đến 4.4 nó không được tuyên bố rõ ràng để thay thế lệnh.
Gilles 'SO- ngừng trở nên xấu xa'

Đúng, trên bash CentOS v7.4.1708 (khá gần đây) là v4.2.46.
dr01

5

Có, ( commands... )là một bashlớp con sẽ thực thi commands...trong một quy trình khác.

Sự khác biệt duy nhất khi bạn có $( commands... )là phần mã này sau khi thực thi commands...sẽ được thay thế bằng mọi thứ được commands...ghi vào stdout.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.