Bash: กระบวนการทดแทนและ stdin


13

บรรทัดต่อไปนี้ชัดเจน:

echo "bla" | foo | bar

แต่สิ่งที่อยู่ด้านล่างทำเช่นเดียวกันหรือไม่

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

ข้อใดfooและbarอ่าน "bla" จาก stdin และทำไม

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

คำตอบ:


9

นั่นคือการพึ่งพาเชลล์และไม่ใช่เอกสาร AFAICS ในkshและbashในกรณีแรกfooจะแบ่งปัน stdin barเดียวกับ echoพวกเขาจะต่อสู้เพื่อการส่งออกของ

ตัวอย่างเช่นใน

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

คุณเห็นหลักฐานที่pasteอ่านบล็อกข้อความทุกอันจากseqเอาท์พุทของในขณะที่trอ่านอีกบล็อก

ด้วยzshมันจะได้รับ stdin ด้านนอก (เว้นแต่ว่ามันเป็นขั้วและเปลือกไม่ได้โต้ตอบในกรณีที่มันถูกเปลี่ยนเส้นทางจาก/dev/null) ksh(ซึ่งเป็นจุดกำเนิด) zshและbashเป็นเชลล์คล้ายบอร์นเดียวที่รองรับการแทนที่กระบวนการ AFAIK

ในecho "bla" | bar < <(foo)ทราบว่าbarstdin 's fooจะเป็นท่อเลี้ยงโดยการส่งออกของ นั่นเป็นพฤติกรรมที่กำหนดไว้อย่างดี ในกรณีที่ปรากฏว่าfoostdin 's เป็นท่อเลี้ยงโดยechoในทุกksh, และzshbash

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

echo bla | { bar <(foo); }

เพื่อให้แน่ใจว่าfoostdin ยังเป็นท่อจากecho(ฉันไม่เห็นว่าทำไมคุณต้องการที่จะทำเช่นนั้น) หรือ:

echo bla | bar <(foo < /dev/null)

เพื่อให้แน่ใจว่าfooจะไม่ได้echoอ่านจากท่อจาก หรือ:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

จะมีfoo's stdin stdin zshนอกเช่นเดียวกับในรุ่นปัจจุบันของ


"ในกรณีนี้ stdin ของ foo คือท่อที่ป้อนโดย echo ใน ksh, zsh และ bash ทั้งหมด" คุณได้ทำการทดสอบสิ่งนี้ด้วยมือตอนนี้หรือเป็นเอกสารที่ไหนสักแห่ง?
etam1024

ไม่ "ในกรณีแรก" ในบรรทัดแรกอ้างถึง `| foo | bar` หรือ `| บาร์ <(foo) `?
Volker Siegel

4

echo "bla" | foo | bar: การส่งออกของecho "bla"ถูกเปลี่ยนเส้นทางไปที่มีการส่งออกจะถูกนำไปfoobar

echo "bla" | bar <(foo): นั่นหนึ่งท่อการส่งออกของไปecho "bla" barแต่barถูกประหารด้วยการโต้เถียง อาร์กิวเมนต์คือพา ธ ไปยังไฟล์ descritor ซึ่งเอาต์พุตของfooจะถูกส่งไปยัง fooเรื่องนี้พฤติกรรมเช่นไฟล์ที่มีการส่งออกของที่ ดังนั้นมันไม่เหมือนกัน

echo "bla" | bar < <(foo): หนึ่งอาจสันนิษฐานว่าผลลัพธ์ของecho "bla"ควรถูกส่งไปbarและคำสั่งทั้งหมดจะเทียบเท่ากับคำแรก แต่นั่นไม่ถูกต้อง ต่อไปนี้จะเกิดขึ้นเพราะการเปลี่ยนเส้นทางการป้อนข้อมูลที่<จะดำเนินการหลังจากที่ท่อ ( |) ก็จะเขียนทับมัน ดังนั้นecho "bla"จะไม่ถูกส่งไปยังแถบ แทนการส่งออกของfooถูกเปลี่ยนเส้นทางเป็น input barมาตรฐาน หากต้องการล้างข้อมูลออกให้ดูคำสั่งและเอาต์พุตต่อไปนี้:

$ echo "bla" | cat < <(echo "foo")
foo

ตามที่คุณเห็นจะถูกแทนที่โดยecho "bla"echo "foo"

ตอนนี้ดูคำสั่งนี้:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

ดังนั้นecho "bar"ถูกส่งไปยังawkซึ่งอ่าน stdin และเพิ่มสตริงand fooลงในเอาต์พุต catผลลัพธ์นี้จะถูกประปา


และคำถามของฉันคือ: "ความจริงที่ว่าawk" แถบ "พฤติกรรมที่กำหนดไว้หรือไม่"
etam1024

ใช่แล้ว. พฤติกรรมเช่นเดียวกับcmd1 < <(cmd2) cmd2 | cmd1
ความโกลาหล

หรือcmd1 | cmd2 | cmd3เหมือนกับcmd1 | cmd3 < <(cmd2)
โกลาหล

3
หากเป็นวิกิพีเดียฉันจะใส่แท็ก "การอ้างอิงที่จำเป็น" ในข้อความของคุณ :) ประเด็นทั้งหมดของคำถามของฉันคือมันใช้งานได้ตามที่คุณพูด แต่ฉันไม่พบเอกสารใด ๆ เกี่ยวกับเรื่องนี้
etam1024
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.