Có, bash
giống như trong ksh
(tính năng đến từ đâu), các quy trình bên trong quy trình thay thế không được chờ đợi (trước khi chạy lệnh tiếp theo trong tập lệnh).
đối với một <(...)
, điều đó thường tốt như trong:
cmd1 <(cmd2)
Shell sẽ chờ đợi cmd1
và cmd1
thường sẽ chờ đợi cho cmd2
đến khi nó đọc cho đến khi hết tập tin trên đường ống được thay thế, và việc kết thúc tập tin đó thường xảy ra khi cmd2
chết. Đó là lý do cùng nhiều vỏ (không bash
) không bận tâm chờ đợi cmd2
trong cmd2 | cmd1
.
Đối cmd1 >(cmd2)
Tuy nhiên,, đó là thường không phải như vậy, vì nó là nhiều cmd2
mà thường chờ cmd1
có như vậy sẽ thường thoát sau đó.
Điều đó đã được sửa trong zsh
đó chờ cmd2
ở đó (nhưng không phải nếu bạn viết nó dưới dạng cmd1 > >(cmd2)
và cmd1
không được dựng sẵn, {cmd1} > >(cmd2)
thay vào đó hãy sử dụng như tài liệu ).
ksh
không chờ đợi theo mặc định, nhưng cho phép bạn chờ nó với wait
nội trang (nó cũng làm cho pid có sẵn $!
, mặc dù điều đó không giúp ích gì nếu bạn làm vậy cmd1 >(cmd2) >(cmd3)
)
rc
(với cmd1 >{cmd2}
cú pháp), giống như ksh
ngoại trừ bạn có thể nhận được các pids của tất cả các quy trình nền với $apids
.
es
(cũng với cmd1 >{cmd2}
) chờ đợi cmd2
như trong zsh
và cũng chờ cmd2
trong <{cmd2}
quá trình chuyển hướng.
bash
không làm cho pid của cmd2
(hoặc chính xác hơn là lớp con như nó chạy cmd2
trong một tiến trình con của lớp con đó mặc dù đó là lệnh cuối cùng ở đó) có sẵn $!
, nhưng không cho phép bạn chờ đợi.
Nếu bạn phải sử dụng bash
, bạn có thể giải quyết vấn đề bằng cách sử dụng lệnh sẽ chờ cả hai lệnh với:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Điều đó làm cho cả hai cmd1
và cmd2
có fd 3 của họ mở ra một đường ống. cat
sẽ chờ kết thúc tập tin ở đầu kia, vì vậy thường sẽ chỉ thoát khi cả hai cmd1
và cmd2
đã chết. Và shell sẽ chờ cat
lệnh đó . Bạn có thể thấy rằng như một mạng lưới để bắt đầu chấm dứt tất cả các quy trình nền (bạn có thể sử dụng nó cho những thứ khác bắt đầu trong nền như với &
, coprocs hoặc thậm chí các lệnh mà nền đó cung cấp, chúng không đóng tất cả các mô tả tệp của chúng như daemon thường làm ).
Lưu ý rằng nhờ quy trình chia nhỏ bị lãng phí đã đề cập ở trên, nó hoạt động ngay cả khi cmd2
đóng fd 3 của nó (các lệnh thường không làm điều đó, nhưng một số thích sudo
hoặc ssh
làm). Các phiên bản trong tương lai bash
cuối cùng có thể thực hiện tối ưu hóa như trong các shell khác. Sau đó, bạn cần một cái gì đó như:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Để đảm bảo vẫn còn một quá trình shell bổ sung với fd 3 mở đó đang chờ sudo
lệnh đó .
Lưu ý rằng cat
sẽ không đọc bất cứ điều gì (vì các quy trình không viết trên fd 3 của họ). Nó chỉ ở đó để đồng bộ hóa. Nó sẽ thực hiện chỉ một read()
cuộc gọi hệ thống sẽ trở lại mà không có gì ở cuối.
Bạn thực sự có thể tránh chạy cat
bằng cách sử dụng thay thế lệnh để thực hiện đồng bộ hóa đường ống:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Lần này, nó là cái vỏ thay vì cat
đọc từ ống có đầu kia mở trên fd 3 cmd1
và cmd2
. Chúng tôi đang sử dụng một phép gán biến để trạng thái thoát cmd1
có sẵn trong $?
.
Hoặc bạn có thể thực hiện thay thế quy trình bằng tay, và sau đó bạn thậm chí có thể sử dụng hệ thống của mình sh
vì điều đó sẽ trở thành cú pháp shell tiêu chuẩn:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
mặc dù lưu ý như đã lưu ý trước đó rằng không phải tất cả các sh
triển khai sẽ đợi cmd1
sau khi cmd2
kết thúc (mặc dù điều đó tốt hơn so với cách khác). Thời gian đó, $?
chứa trạng thái thoát của cmd2
; mặc dù bash
và zsh
làm cho cmd1
trạng thái thoát có sẵn trong ${PIPESTATUS[0]}
và $pipestatus[1]
tương ứng (xem thêm pipefail
tùy chọn trong một số shell để $?
có thể báo cáo sự cố của các thành phần đường ống khác với lần cuối)
Lưu ý rằng yash
có vấn đề tương tự với tính năng chuyển hướng quy trình của nó . cmd1 >(cmd2)
sẽ được viết cmd1 /dev/fd/3 3>(cmd2)
ở đó. Nhưng cmd2
không được chờ đợi và bạn cũng không thể sử dụng wait
để chờ đợi và pid của nó cũng không có sẵn trong $!
biến. Bạn sẽ sử dụng cùng một công việc xung quanh như cho bash
.