exec โต้ตอบกับไพพ์ในเชลล์อย่างไร?

Oct 27 2020

สมมติว่าฉันมีสิ่งต่อไปนี้ในจุดเริ่มต้นของรหัสของฉัน:

exec < file

มันหมายความว่าถ้าผมเข้าใจถูกต้องว่าคำสั่งทั้งหมดพยายามที่จะอ่านจาก stdin fileจะอ่านจริงจาก

แต่ถ้ามีcmd1 | cmd2จะcmd2อ่านจากcmd1เอาต์พุตหรือfile?

คำตอบ

2 KamilMaciorowski Oct 27 2020 at 14:21

หมายความว่าถ้าฉันเข้าใจถูกต้องคำสั่งทั้งหมดที่พยายามอ่านจาก stdin จะอ่านจากไฟล์จริงๆ

คำสั่งอ่านจาก stdin ของมันจะอ่านจากแฟ้มปกติถ้ามัน stdin เกิดขึ้นจะเป็นแฟ้มปกติ คำสั่งอ่านจาก stdin ของมันจะอ่านจากขั้วหรือ FIFO (ซึ่งยังไฟล์ ) ถ้ามัน stdin เกิดขึ้นจะเป็นขั้วหรือ FIFO ตามลำดับ

Stdin ของคำสั่งหนึ่งอาจแตกต่างจาก stdin ของคำสั่งอื่น

ในสคริปต์ตีความโดยbash, exec < fileเปลี่ยนเส้นทาง stdin นี้โดยเฉพาะอย่างยิ่งbashกระบวนการเท่านั้น คำสั่งในภายหลังจะได้รับผลกระทบหากสืบทอด stdin แต่การสืบทอดจะเกิดขึ้นในลักษณะเดียวกันไม่ว่าคุณจะใช้exec < fileหรือไม่ก็ตาม

หากคุณทำงานเพียงcmd0แล้วมันจะได้รับมรดก stdin และ stdout (และ stderr) bashจากการตีความ มันไม่เกี่ยวข้องกันว่า stdin และ stdout ของการตีความbashคืออะไร กลไกจะเหมือนกันเสมอ

หากคุณทำงานcmd1 | cmd2 | … | cmdNแล้วcmd1จะได้รับมรดก stdin จากการตีความbashและcmdNจะได้รับมรดก stdout bashจากการตีความ stdins และ stdouts อื่น ๆ จะสร้างไปป์ไลน์ (stdout of cmd1connected to stdin of cmd2เป็นต้น) มันไม่เกี่ยวข้องกันว่า stdin และ stdout ของการตีความbashคืออะไร กลไกจะเหมือนกันเสมอ

ข้อเท็จจริงที่คุณใช้exec < fileไม่เกี่ยวข้องกับกลไก บางคำสั่ง (s) จะได้รับมรดก stdin และ / หรือ stdout bashจากการตีความ โดยไม่ต้องexec < fileพวกเขาจะได้รับมรดกบางสิ่งบางอย่าง ด้วยการexec < fileที่พวกเขาจะได้รับมรดกอย่างอื่นเป็น stdin

วิธีการนี้exec < fileจะมีผลต่อคำสั่งบางอย่าง แต่เพียงคำสั่งที่สืบทอด stdin bashจากการตีความ ของคุณcmd1สืบทอดมาตรฐานของการตีความbashแต่cmd2ไม่ได้รับ

สมมติว่าคุณcmd2อ่านจาก stdin มันจะอ่านจากผลลัพธ์ของcmd1. ก่อนหน้าexec < fileนี้ไม่สำคัญ (หมายเหตุโดยทั่วไปcmd2อาจเปลี่ยนเส้นทางหรือละเว้นหรือปิด stdin คำสั่งที่ออกแบบมาเพื่อทำงานในไปป์ไลน์จะไม่ทำเช่นนี้เว้นแต่จะแจ้งให้)

คุณสามารถทดสอบสิ่งนี้ในสคริปต์:

#!/bin/bash
# Don't run this in an interactive shell. Run as a script.
exec < /etc/fstab
echo foo | cat
wc -l

โปรดทราบว่าหากคุณวางรหัสด้านบนในแบบโต้ตอบbashคุณจะเปลี่ยน stdin ของbashตัวมันเองและในที่สุดก็จะออกเมื่อ EOF เพื่อความสะดวกของคุณด้านล่างนี้เป็นเวอร์ชันที่สามารถเรียกใช้ในเชลล์แบบโต้ตอบได้โดยไม่ต้องยุติ:

bash -c '
   exec < /etc/fstab
   echo foo | cat
   wc -l
'

ผลลัพธ์ควรเป็นfoo(พิสูจน์ว่าcatอ่านผลลัพธ์ของecho) ตามด้วยตัวเลขที่เป็นจำนวนบรรทัดในของคุณfstab(พิสูจน์ว่าwcอ่านจากfstab)