Câu trả lời:
$(…)
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:
( … )
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.… &
tạo một lớp con và không chờ nó kết thúc.… | …
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 lastpipe
tù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.$(…)
(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.)<(…)
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.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.${...}
trong câu trả lời?
command | { read line; … }
(tùy thuộc vào vỏ, line
có 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.
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
command
trong môi trường lớp con [...]
bash
trang 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.