Được rồi, hãy phá vỡ điều này. Một subshell thực thi nội dung của nó trong một chuỗi (nghĩa là nó nhóm chúng). Điều này thực sự có ý nghĩa trực quan như một lớp con được tạo ra đơn giản bằng cách bao quanh chuỗi lệnh với ()
. Nhưng, ngoài nội dung của lớp con được nhóm lại với nhau khi thực thi, bạn vẫn có thể sử dụng một lớp con như thể đó là một lệnh đơn. Đó là, một subshell vẫn có một stdin
, stdout
và stderr
vì vậy bạn có thể dẫn mọi thứ đến và đi từ một subshell.
Mặt khác, thay thế lệnh không giống như chỉ đơn giản là xâu chuỗi các lệnh lại với nhau. Thay vào đó, thay thế lệnh có nghĩa là hoạt động giống như một truy cập biến nhưng với một lệnh gọi hàm. Các biến, không giống như các lệnh, không có các bộ mô tả tệp tiêu chuẩn, do đó bạn không thể dẫn bất cứ thứ gì đến hoặc từ một biến (nói chung), và điều tương tự cũng đúng với các thay thế lệnh.
Để cố gắng làm cho điều này rõ ràng hơn, những gì sau đây là một tập hợp các ví dụ có thể không rõ ràng (nhưng chính xác) và một tập hợp, những gì tôi nghĩ có thể là, ví dụ dễ hiểu hơn.
Hãy nói rằng date -u
lệnh đưa ra như sau:
Thu Jul 2 13:42:27 UTC 2015
Nhưng, chúng tôi muốn thao tác đầu ra của lệnh này. Vì vậy, hãy đặt nó vào một cái gì đó như sed
:
$ date -u | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Wow, thật là vui! Những điều sau đây hoàn toàn tương đương với ở trên (loại bỏ một số khác biệt về môi trường mà bạn có thể đọc trong các trang hướng dẫn về vỏ của bạn):
$ (date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Điều đó không có gì đáng ngạc nhiên vì tất cả những gì chúng tôi đã làm là nhóm date -u
. Tuy nhiên, nếu chúng ta làm như sau, chúng ta sẽ nhận được một cái gì đó có vẻ hơi kỳ lạ lúc đầu:
$ $(date -u) | sed -e 's/ / /g'
command not found: Thu
Điều này là do $(date -u)
tương đương với việc gõ chính xác những gì date -u
đầu ra. Vì vậy, ở trên là tương đương với sau đây:
$ Thu Jul 2 13:42:27 UTC 2015 | sed -e 's/ / /g'
Tất nhiên, đó sẽ là lỗi vì Thu
không phải là lệnh (ít nhất không phải là lệnh tôi biết); và nó chắc chắn không dẫn đường gì cả stdout
(vì vậy sed
sẽ không bao giờ nhận được bất kỳ đầu vào nào).
Nhưng, vì chúng ta biết rằng các thay thế lệnh hoạt động giống như các biến, chúng ta có thể dễ dàng khắc phục vấn đề này bởi vì chúng ta biết cách chuyển giá trị của một biến sang một lệnh khác:
$ echo $(date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Nhưng, như với bất kỳ biến nào trong bash , có lẽ bạn nên trích dẫn thay thế lệnh bằng ""
.
Bây giờ, cho ví dụ có lẽ đơn giản hơn; xem xét những điều sau đây
$ pwd
/home/hypothetical
$ echo pwd
pwd
$ echo "$(pwd)"
/home/hypothetical
$ echo "$HOME"
/home/hypothetical
$ echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
$ (pwd)
/home/hypothetical
Tôi không chắc làm thế nào để mô tả nó đơn giản hơn thế. Sự thay thế lệnh hoạt động giống như một truy cập biến trong đó lớp con vẫn hoạt động như một lệnh.
netcat
vì nó sẽ chỉ là văn bản trống. Nếu bạn, ví dụ, được thêm vàoecho
trước khi thay thế lệnh bắt đầu, bạn có thể thấy rằng nó hoạt động.