คุณรู้ว่าฉันไม่มั่นใจว่าคุณจำเป็นต้องมีห่วงข้อเสนอแนะซ้ำ ๆ เป็นแผนภาพภาพของคุณมากเท่าที่คุณสามารถใช้ ไพพ์ไลน์แบบถาวรระหว่างโพรเซส จากนั้นอีกครั้งอาจมีความแตกต่างไม่มากนัก - เมื่อคุณเปิดบรรทัดบนตัวประมวลผลร่วมคุณสามารถใช้ลูปลักษณะทั่วไปเพียงแค่เขียนข้อมูลลงไปและอ่านข้อมูลจากมันโดยไม่ต้องทำอะไรผิดไปมาก
ในสถานที่แรกมันจะปรากฏว่าbc
เป็นผู้สมัครที่สำคัญสำหรับกระบวนการร่วมสำหรับคุณ ในbc
คุณสามารถdefine
ทำหน้าที่ที่สามารถทำสิ่งที่คุณขอได้ใน pseudocode ของคุณ ตัวอย่างเช่นฟังก์ชั่นที่ง่ายมากที่จะทำสิ่งนี้อาจมีลักษณะ:
printf '%s()\n' b c a |
3<&0 <&- bc -l <<\IN <&3
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
IN
... ซึ่งจะพิมพ์ ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
แต่แน่นอนมันไม่ได้สุดท้าย ทันทีที่ subshell รับผิดชอบการprintf
หยุดทำงานของไพพ์(หลังจากprintf
เขียนa()\n
ไปที่ไพพ์แล้ว) ไพพ์จะถูกดึงลงและbc
อินพุตของปิดลงและมันก็จะหยุดทำงานเช่นกัน นั่นไม่ค่อยมีประโยชน์เท่าที่ควร
@derobert ได้พูดถึงFIFOแล้วว่าสามารถทำได้โดยการสร้างไฟล์ไปป์ที่มีชื่อพร้อมกับmkfifo
ยูทิลิตี้ สิ่งเหล่านี้เป็นเพียงท่อเช่นกันยกเว้นเคอร์เนลระบบเชื่อมโยงรายการระบบไฟล์ไปยังปลายทั้งสอง สิ่งเหล่านี้มีประโยชน์มาก แต่มันจะดีกว่าถ้าคุณมีท่อได้โดยไม่ต้องเสี่ยงว่ามันจะถูกสอดแนมในระบบไฟล์
เมื่อมันเกิดขึ้นเปลือกของคุณทำสิ่งนี้มากมาย หากคุณใช้เชลล์ที่ดำเนินการทดแทนกระบวนการคุณมีวิธีที่ง่ายมากในการได้รับไพพ์ที่คงทน - ซึ่งเป็นชนิดที่คุณอาจกำหนดให้กับกระบวนการแบ็กกราวด์ที่คุณสามารถสื่อสารได้
ใน bash
ตัวอย่างเช่นคุณสามารถดูวิธีการทำงานของกระบวนการเปลี่ยนตัว:
bash -cx ': <(:)'
+ : /dev/fd/63
คุณเห็นมันจริงๆคือเปลี่ยนตัว เปลือกทดแทนค่าระหว่างการขยายตัวที่สอดคล้องกับเส้นทางไปยังเชื่อมโยงไปยังท่อ คุณสามารถใช้ประโยชน์จากสิ่งนั้นได้ - คุณไม่จำเป็นต้อง จำกัด ให้ใช้ไพพ์นั้นเพื่อสื่อสารกับกระบวนการใดก็ตามที่ทำงานอยู่ภายใน()
ทดแทนตัวเอง ...
bash -c '
eval "exec 3<>"<(:) "4<>"<(:)
cat <&4 >&3 &
echo hey cat >&4
read hiback <&3
echo "$hiback" here'
... ที่พิมพ์ ...
hey cat here
ตอนนี้ฉันรู้ว่าเชลล์ที่แตกต่างกันทำสิ่งที่ประมวลผลร่วมในวิธีที่ต่างกัน - และมีไวยากรณ์เฉพาะในbash
การตั้งค่าหนึ่ง(และอาจเป็นหนึ่งสำหรับzsh
เช่นกัน) - แต่ฉันไม่รู้ว่าสิ่งเหล่านั้นทำงานอย่างไร ฉันเพิ่งรู้ว่าคุณสามารถใช้ไวยากรณ์ข้างต้นเพื่อทำสิ่งเดียวกันโดยไม่ต้องใช้แท่นขุดเจาะทั้งในbash
และzsh
- และคุณสามารถทำสิ่งที่คล้ายกันมากในdash
และbusybox ash
เพื่อให้บรรลุวัตถุประสงค์เดียวกันกับเอกสารที่นี่(เพราะdash
และbusybox
ทำที่นี่ - เอกสารที่มีท่อมากกว่าชั่วคราวเป็นไฟล์อีกสองคนทำ)
ดังนั้นเมื่อนำไปใช้กับbc
...
eval "exec 3<>"<(:) "4<>"<(:)
bc -l <<\INIT <&4 >&3 &
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
INIT
export BCOUT=3 BCIN=4 BCPID="$!"
... นั่นเป็นส่วนที่ยาก และนี่คือส่วนที่สนุก ...
set --
until [ "$#" -eq 10 ]
do printf '%s()\n' b c a >&"$BCIN"
set "$@" "$(head -n 3 <&"$BCOUT")"
done; printf %s\\n "$@"
... ที่พิมพ์ ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
#...24 more lines...
b=3.92307618030433853649
c=-.70433330413228041035
a=.29566669586771958965
... และมันยังคงทำงานอยู่ ...
echo a >&"$BCIN"
read a <&"$BCOUT"
echo "$a"
... ซึ่งเพิ่งได้รับฉันค่าสุดท้ายสำหรับbc
's a
มากกว่าการเรียกa()
ฟังก์ชั่นเพื่อเพิ่มมันและพิมพ์ ...
.29566669586771958965
ในความเป็นจริงมันจะยังคงทำงานต่อไปจนกว่าฉันจะฆ่ามันและทำลายท่อ IPC ของมัน ...
kill "$BCPID"; exec 3>&- 4>&-
unset BCPID BCIN BCOUT