วิธีการพกพา (POSIX) เพื่อให้เกิดการทดแทนกระบวนการคืออะไร?


25

เชลล์บางตัวbashสนับสนุนการทดแทนกระบวนการซึ่งเป็นวิธีการนำเสนอผลลัพธ์กระบวนการเป็นไฟล์เช่นนี้:

$ diff <(sort file1) <(sort file2)

อย่างไรก็ตามโครงสร้างนี้ไม่ใช่POSIXและไม่ใช่พกพา วิธีสามารถดำเนินการเปลี่ยนตัวทำได้ในPOSIXลักษณะที่เป็นมิตร (เช่นหนึ่งซึ่งทำงาน/bin/sh) ?

หมายเหตุ: คำถามไม่ได้ถามว่าจะแตกไฟล์ที่จัดเรียงสองไฟล์ได้อย่างไรซึ่งเป็นเพียงตัวอย่างที่ประดิษฐ์ขึ้นเพื่อสาธิตการทดแทนกระบวนการ !


mywiki.wooledge.org/ProcessSubstitutionมีหมายเหตุว่าอาจใช้mywiki.wooledge.org/NamedPipes ..
Sundeep

2
ดูเพิ่มเติมที่unix.stackexchange.com/a/43536/117549
Jeff Schaller

1
POSIX ไม่จำเป็นต้อง/bin/shเป็นเชลล์ POSIX เพียงว่ามีคำสั่งที่เรียกว่าshบางแห่งซึ่งในสภาพแวดล้อมที่เหมาะสมนั้นเป็นไปตาม POSIX ยกตัวอย่างเช่นบน Solaris 10 /bin/shไม่ได้เป็นเปลือก POSIX มันเป็นโบราณบอร์นเปลือกหอยและเปลือก POSIX /usr/xpg4/bin/shอยู่ใน
Stéphane Chazelas

คำตอบ:


17

คุณลักษณะดังกล่าวได้รับการแนะนำโดยksh(บันทึกเป็นครั้งแรกใน ksh86) และใช้ประโยชน์จาก/dev/fd/nคุณลักษณะนี้ (เพิ่มอย่างเป็นอิสระในระบบ BSD และ AT&T บางรุ่นก่อนหน้านี้) ในkshและมากถึง ksh93u มันจะไม่ทำงานจนกว่าระบบของคุณจะรองรับ / dev / fd / n zsh, bash และksh93u+ขึ้นไปสามารถใช้ประโยชน์จาก pipe ที่มีชื่อชั่วคราว (ชื่อ pipes ที่ถูกเพิ่มเข้ามาใน SysIII ฉันเชื่อ) โดยที่ / dev / fd / n ไม่สามารถใช้ได้

บนระบบที่มีให้บริการ (POSIX ไม่ได้ระบุไว้) คุณสามารถทำการทดแทนตัวเอง ( ) ด้วย:/dev/fd/ndiff <(cmd1) <(cmd2)

{
  cmd1 4<&- | {
    # in here fd 3 points to the reading end of the pipe
    # from cmd1, while fd 0 has been restored from the original
    # stdin (saved on fd 4, now closed as no longer needed)

    cmd2 3<&- | diff /dev/fd/3 -

  } 3<&0 <&4 4<&- # restore the original stdin for cmd2

} 4<&0 # save a copy of stdin for cmd2

อย่างไรก็ตามมันไม่สามารถใช้งานksh93บน Linux ได้เนื่องจากมีการใช้ shell shell กับ socketpairs แทนการเปิดไป/dev/fd/3ที่ fd 3 คะแนนไปยัง socket ไม่ทำงานบน Linux

แม้ว่า POSIX ไม่ได้ระบุ มันระบุชื่อไปป์ ไปป์ที่มีชื่อทำงานเหมือนกับไพพ์ปกติยกเว้นว่าคุณสามารถเข้าถึงได้จากระบบไฟล์ ปัญหาที่นี่คือคุณต้องสร้างคนชั่วคราวและทำความสะอาดหลังจากนั้นซึ่งยากที่จะทำอย่างน่าเชื่อถือโดยเฉพาะอย่างยิ่งการพิจารณาว่า POSIX ไม่มีกลไกมาตรฐาน (เช่นที่พบในบางระบบ) เพื่อสร้างไฟล์หรือไดเรกทอรีชั่วคราวและการจัดการสัญญาณแบบพกพา (ทำความสะอาดเมื่อวางสายหรือฆ่า) ก็ยากที่จะทำแบบพกพา/dev/fd/nmktemp -d

คุณสามารถทำสิ่งที่ชอบ:

tmpfifo() (
  n=0
  until
    fifo=$1.$$.$n
    mkfifo -m 600 -- "$fifo" 2> /dev/null
  do
    n=$((n + 1))
    # give up after 20 attempts as it could be a permanent condition
    # that prevents us from creating fifos. You'd need to raise that
    # limit if you intend to create (and use at the same time)
    # more than 20 fifos in your script
    [ "$n" -lt 20 ] || exit 1
  done
  printf '%s\n' "$fifo"
)

cleanup() { rm -f -- "$fifo"; }
fifo=$(tmpfifo /tmp/fifo) || exit

cmd2 > "$fifo" & cmd1 | diff - "$fifo"
rm -f -- "$fifo"

(ไม่ได้ดูแลการจัดการสัญญาณที่นี่)


ตัวอย่างไปป์ที่ระบุชื่อนั้นชัดเจนสำหรับฉัน (ฉันเดาว่า 10 เป็นข้อ จำกัด โดยพลการหรือไม่) แต่ฉันไม่สามารถเข้าใจ/dev/fd/nตัวอย่างของคุณได้ เหตุใด descriptor 4 จึงปิดสองครั้ง (และเป็นตัวบ่งบอก 3. ) ฉันหลงทาง
Wildcard

@ Wildcard ปิดสำหรับคำสั่งที่ไม่ต้องการ นี่ต้องการเพียงความแตกต่างที่ fd 3 ไม่จำเป็นต้องใช้ fd 4 มันถูกใช้เพื่อเผยแพร่ stdin ดั้งเดิมไปที่cmd2( dup2(0,4)ด้านนอก{...}เรียกคืนพร้อมกับdup2(4,0)ด้านใน{...})
Stéphane Chazelas

คุณสามารถใช้mktemp -dเพื่อช่วยให้แน่ใจว่าคุณจะได้รับ FIFO เพราะไม่มีใครควรเขียนไปยังไดเรกทอรีชั่วคราวแบบสุ่มใหม่ของคุณ
Daniel H

@DanielH mktemp -dผมพูดถึงอยู่แล้ว แต่นั่นไม่ใช่คำสั่งมาตรฐาน / POSIX
Stéphane Chazelas

อืมฉันไม่ได้ตระหนักถึงสิ่งนั้น อุ่ย การค้นหาอย่างรวดเร็วดูเหมือนจะแสดงว่าระบบส่วนใหญ่รองรับดังนั้นจึงอาจยังพกพาได้ แต่ก็ไม่ใช่ POSIX
Daniel H

-1

หากจำเป็นเพื่อหลีกเลี่ยงตัวแปรที่หายไปในประโยชน์cmd | while read A B Cแทน:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done < <(cmd)
echo "$VAR"

คุณสามารถใช้ได้:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done << EndOfText
`cmd`
EndOfText
echo "$VAR"

ดังนั้นเพื่อตอบคำถาม:

sort file1 | diff /dev/stdin /dev/stdout 2<<EOT
`sort file2`
EOT
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.