ทั้งใน
<file.txt tee >(grep LITERAL) >(wc -l) >/dev/null
และ:
{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1
ของทั้งหมดtee
, grep
และwc
จะเริ่มต้นพร้อมกัน สิ่งที่สำคัญคือสิ่งที่เกิดขึ้นในตอนท้าย
wc
จะพิมพ์ผลลัพธ์เฉพาะเมื่อเห็นจุดสิ้นสุดไฟล์ในอินพุตมาตรฐาน ในกรณีแรกนั่นคือเมื่อจบการทำงานtee
เนื่องจากtee
จะปิดfd
ลงที่ปลายอีกด้านของไพพ์ที่wc
อ่านจาก (เริ่มต้นโดยการทดแทนกระบวนการ) ไม่มีการรับประกันว่าgrep
จะอ่านอินพุตทั้งหมดในเวลานั้นให้เขียนเอาต์พุตของมันเพียงอย่างเดียว (เนื่องจากท่อสามารถเก็บข้อมูลได้ค่อนข้างมากและwc
น่าจะเร็วกว่าgrep
)
ในกรณีที่สองwc
จะเห็นจุดสิ้นสุดไฟล์เมื่อผู้เขียนทั้งหมดไปยังไปป์ที่กำลังอ่านจากปิดส่วนท้ายของไพพ์ ในกรณีนั้นมีนักเขียนหลายคน tee
(ผ่าน fd เปิด/dev/fd/3
และผ่าน fd 3) และgrep
ซึ่งfd
เปิด 3 ไปยังท่อไปที่wc
(แม้ว่าจะไม่ได้ใช้ประโยชน์จากมันให้เขียนเพียงอย่างเดียว) ภายใน{
มีแนวโน้มที่จะก่อให้เกิดกระบวนการ subshell พิเศษที่จะมีfd
3 เปิดและจะรอให้ทั้งสองและtee
grep
นั่นหมายความว่าwc
จะเขียนหมายเลขบรรทัดหลังจากที่grep
ออกแล้วเท่านั้น
หากคุณเขียนวิธีที่ถูกต้องนั่นคือปิด fds ที่ไม่ต้องการเปิด:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
จากนั้นคำสั่งจะไม่ได้รับการรับประกันในเชลล์ที่ปรับกระบวนการย่อยให้เหมาะสม อย่างไรก็ตามเชลล์เพียงตัวเดียวที่ฉันรู้ว่ามันใช้ksh93
แต่ksh93
ใช้ซ็อกเก็ตคู่สำหรับไพพ์ดังนั้นมัน/dev/fd/3
จะไม่ทำงานบน Linux อย่างน้อย
หากต้องการดูว่ากระบวนการใดที่กำลังทำงานอยู่คุณสามารถแทนที่grep
ด้วย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
ด้วยbash
, คุณสามารถเห็นกระบวนการเชลล์พิเศษ, และคุณสามารถดูได้ว่ามันมีไปป์ที่เปิดใน fd 3 ด้วย:
$ (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>&-
หมายความว่า fd 4 ดูเหมือนจะใช้งานและปิดแล้ว