Ở cả hai
<file.txt tee >(grep LITERAL) >(wc -l) >/dev/null
Và:
{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1
Tất cả tee, grepvà wcđược bắt đầu đồng thời. Điều quan trọng sau đó là những gì xảy ra ở cuối.
wcsẽ chỉ in kết quả khi thấy tập tin cuối vào đầu vào tiêu chuẩn của nó. Trong trường hợp đầu tiên, đó là khi teethoát ra, bởi vì sau đó teesẽ đóng nó fdở đầu kia của ống wcđang đọc (bắt đầu bằng quá trình thay thế quy trình). Không có gì đảm bảo rằng grepsẽ đọc tất cả đầu vào của nó vào thời điểm đó, chứ đừng nói đến việc viết đầu ra của nó (với điều kiện là các đường ống có thể chứa một lượng dữ liệu khá lớn và wccó khả năng sẽ nhanh hơn grep)
Trong trường hợp thứ hai, wcsẽ thấy phần cuối của tập tin khi tất cả các nhà văn đến đường ống mà nó đang đọc đã đóng đầu ống của họ. Trong trường hợp đó, có một số nhà văn. tee(thông qua mở fd trên /dev/fd/3và qua fd của nó 3) và greptrong đó cũng có nó fd3 mở cửa cho các đường ống để wc(mặc dù nó không được thực hiện bất kỳ việc sử dụng nó, hãy để một mình ghi vào nó). Phần bên trong {có thể sẽ gây ra một quá trình subshell thêm cũng sẽ có fd3 mở và sẽ chờ cho cả hai teevà grep.
Điều đó có nghĩa là wcsẽ chỉ viết số dòng của nó sau khi grepđã thoát.
Nếu bạn đã viết nó theo cách thích hợp, đó là bằng cách đóng các fds không cần mở:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
Sau đó, thứ tự sẽ không được đảm bảo trong các vỏ tối ưu hóa quá trình subshell. Tuy nhiên, lớp vỏ duy nhất mà tôi biết là vậy ksh93nhưng ksh93sử dụng các cặp ổ cắm cho các đường ống, vì vậy /dev/fd/3ít nhất sẽ không hoạt động trên Linux.
Để xem những tiến trình nào đang chạy, bạn có thể thay thế grepbằng ps:
$ { { <file.txt tee /dev/fd/3 4>&- | ps -H >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
PID TTY TIME CMD
8727 pts/5 00:00:00 bash
8815 pts/5 00:00:00 bash
8817 pts/5 00:00:00 tee
8818 pts/5 00:00:00 ps
8816 pts/5 00:00:00 wc
Với bash, bạn có thể thấy quá trình shell bổ sung đó và bạn có thể thấy nó cũng có đường ống được mở trên fd 3 với:
$ (p=$BASHPID; { { <file.txt tee /dev/fd/3 4>&- | lsof -ag "$p" -d3 >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1)
COMMAND PID PGID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 9843 9842 chazelas 3w FIFO 0,8 0t0 153304 pipe
tee 9845 9842 chazelas 3w FIFO 0,8 0t0 153304 pipe
lsof 9846 9842 chazelas 3r DIR 0,3 0 1 /proc
grep LITERAL >&4 3>&- 4>&-có nghĩa là gì , fd 4 dường như được sử dụng và đóng?