คุณใช้คำสั่ง coproc ในเชลล์ต่าง ๆ ได้อย่างไร?


คำตอบ:


118

กระบวนการร่วมเป็นkshคุณลักษณะ (มีอยู่แล้วksh88) zshมีคุณลักษณะตั้งแต่เริ่มต้น (ต้น 90 ต้น) ในขณะที่เพิ่งเพิ่มเข้ามาbashใน4.0(2009)

อย่างไรก็ตามพฤติกรรมและส่วนต่อประสานนั้นแตกต่างกันอย่างมากระหว่าง 3 shells

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

ทำด้วยไพพ์ที่ไม่มีชื่อซึ่งมีเชลล์และซ็อกเก็ตแพร์ส่วนใหญ่ที่มี ksh93 รุ่นล่าสุดในบางระบบ

ในa | cmd | b, aฟีดข้อมูลcmdและbอ่านเอาท์พุท เล่นcmdในฐานะผู้ร่วมกระบวนการช่วยให้เปลือกเป็นทั้งและab

ksh co-processes

ในkshคุณเริ่ม coprocess เป็น:

cmd |&

คุณป้อนข้อมูลcmdด้วยการทำสิ่งต่าง ๆ เช่น:

echo test >&p

หรือ

print -p test

และอ่านcmdผลลัพธ์ด้วยสิ่งต่าง ๆ เช่น:

read var <&p

หรือ

read -p var

cmdจะเริ่มต้นเป็นงานพื้นหลังใด ๆ คุณสามารถใช้fg, bg, killเกี่ยวกับมันและดูมันด้วยหรือผ่านทาง%job-number$!

หากต้องการปิดปลายการเขียนของไปป์cmdอ่านจากคุณสามารถทำได้:

exec 3>&p 3>&-

และเพื่อปิดส่วนท้ายของการอ่านของไพพ์อื่น ๆ (อันที่หนึ่งcmdเขียนถึง):

exec 3<&p 3<&-

คุณไม่สามารถเริ่มต้นกระบวนการร่วมที่สองเว้นแต่ว่าคุณจะบันทึกไฟล์ไปป์อธิบายไปยัง fds อื่น ๆ ก่อน ตัวอย่างเช่น

tr a b |&
exec 3>&p 4<&p
tr b c |&
echo aaa >&3
echo bbb >&p

zsh co-processes

ในผู้ร่วมกระบวนการเกือบจะเหมือนกันกับผู้ที่อยู่ในzsh kshข้อแตกต่างที่แท้จริงคือzshกระบวนการร่วมเริ่มต้นด้วยcoprocคำหลัก

coproc cmd
echo test >&p
read var <&p
print -p test
read -p var

การทำ:

exec 3>&p

หมายเหตุ: สิ่งนี้จะไม่ย้ายcoprocไฟล์ descriptor ไปยัง fd 3(เหมือนในksh) แต่ทำซ้ำ ดังนั้นไม่มีทางที่ชัดเจนที่จะปิดการให้อาหารหรือการอ่านท่ออื่น ๆ เริ่มต้นอีก coproc

ตัวอย่างเช่นหากต้องการปิดท้ายการให้อาหาร:

coproc tr a b
echo aaaa >&p # send some data

exec 4<&p     # preserve the reading end on fd 4
coproc :      # start a new short-lived coproc (runs the null command)

cat <&4       # read the output of the first coproc

นอกเหนือไปจากท่อร่วมตามกระบวนการ, zsh(ตั้งแต่ 3.1.6-dev19 การปล่อยตัวในปี 2000) มีโครงสร้างหลอก TTY expectตามชอบ ในการโต้ตอบกับโปรแกรมส่วนใหญ่กระบวนการร่วมแบบ ksh จะไม่ทำงานเนื่องจากโปรแกรมเริ่มบัฟเฟอร์เมื่อเอาต์พุตของพวกเขาเป็นไพพ์

นี่คือตัวอย่างบางส่วน.

เริ่มกระบวนการร่วมx:

zmodload zsh/zpty
zpty x cmd

(ที่นี่cmdเป็นคำสั่งง่ายๆ แต่คุณสามารถทำสิ่งต่าง ๆ ด้วยevalหรือฟังก์ชั่นนักเล่นได้)

ฟีดข้อมูลร่วมกระบวนการ:

zpty -w x some data

อ่านข้อมูลร่วมกระบวนการ (ในกรณีที่ง่ายที่สุด):

zpty -r x var

เช่นเดียวกับexpectมันสามารถรอผลลัพธ์บางส่วนจากกระบวนการร่วมที่ตรงกับรูปแบบที่กำหนด

bash co-processes

ไวยากรณ์ของ bash นั้นใหม่กว่ามากและสร้างขึ้นจากคุณลักษณะใหม่ที่เพิ่งเพิ่มเข้าไปใน ksh93, bash และ zsh มันมีไวยากรณ์เพื่ออนุญาตการจัดการของ file descriptor ที่จัดสรรแบบไดนามิกสูงกว่า 10

bashมีพื้นฐาน coprocไวยากรณ์และขยายหนึ่ง

ไวยากรณ์พื้นฐาน

ไวยากรณ์พื้นฐานสำหรับการเริ่มต้นร่วมกระบวนการดูเหมือนzsh's:

coproc cmd

ในkshหรือzshท่อไปและกลับจากร่วมกระบวนการมีการเข้าถึงด้วยและ>&p<&p

แต่ในbashไฟล์ descriptors ของไปป์จากกระบวนการร่วมและไปป์อื่น ๆ ไปยัง co-proccess จะถูกส่งกลับใน$COPROCอาร์เรย์ (ตามลำดับ${COPROC[0]}และ${COPROC[1]}ดังนั้น ...

ฟีดข้อมูลไปยังกระบวนการร่วม:

echo xxx >&"${COPROC[1]}"

อ่านข้อมูลจากกระบวนการร่วม:

read var <&"${COPROC[0]}"

ด้วยไวยากรณ์พื้นฐานคุณสามารถเริ่มต้นกระบวนการร่วมได้ครั้งละหนึ่งกระบวนการเท่านั้น

ไวยากรณ์เพิ่มเติม

ในไวยากรณ์เพิ่มเติมคุณสามารถตั้งชื่อกระบวนการร่วมของคุณ (เช่นในzshzpty co-proccesses):

coproc mycoproc { cmd; }

คำสั่งที่มีจะเป็นคำสั่งผสม (สังเกตว่าตัวอย่างด้านบนทำให้ระลึกถึงfunction f { ...; })

เวลานี้อธิบายไฟล์ที่อยู่ในและ${mycoproc[0]}${mycoproc[1]}

คุณสามารถเริ่มต้นกระบวนการร่วมได้มากกว่าหนึ่งกระบวนการในแต่ละครั้ง แต่คุณจะได้รับคำเตือนเมื่อคุณเริ่มกระบวนการร่วมในขณะที่ยังทำงานอยู่ (แม้อยู่ในโหมดไม่โต้ตอบ)

คุณสามารถปิดไฟล์ descriptors เมื่อใช้ไวยากรณ์เพิ่มเติม

coproc tr { tr a b; }
echo aaa >&"${tr[1]}"

exec {tr[1]}>&-

cat <&"${tr[0]}"

โปรดทราบว่าการปิดวิธีนี้จะไม่ทำงานในเวอร์ชันทุบตีก่อนหน้า 4.3 ซึ่งคุณต้องเขียนแทน:

fd=${tr[1]}
exec {fd}>&-

เช่นเดียวกับในkshและzshคำอธิบายไฟล์ไปป์เหล่านั้นจะถูกทำเครื่องหมายเป็น close-on-exec

แต่ในbashวิธีเดียวที่จะผ่านเหล่านั้นไปยังคำสั่งดำเนินการคือการทำซ้ำพวกเขาที่จะ FDS 0, หรือ1 2ที่ จำกัด จำนวนกระบวนการร่วมที่คุณสามารถโต้ตอบด้วยสำหรับคำสั่งเดียว (ดูตัวอย่างด้านล่าง)

กระบวนการ yash และการเปลี่ยนเส้นทางไปป์ไลน์

yashไม่ได้มีคุณสมบัติร่วมกระบวนการต่อ se แต่แนวคิดเดียวกันสามารถดำเนินการกับของท่อและกระบวนการคุณสมบัติการเปลี่ยนเส้นทาง yashมีส่วนต่อประสานกับการpipe()เรียกของระบบดังนั้นสิ่งนี้สามารถทำได้ค่อนข้างง่ายด้วยมือที่นั่น

คุณจะเริ่มต้นกระบวนการร่วมกับ:

exec 5>>|4 3>(cmd >&5 4<&- 5>&-) 5>&-

สิ่งแรกที่สร้างpipe(4,5)(5 ปลายการเขียน 4 ส่วนปลายอ่าน) จากนั้นเปลี่ยนเส้นทาง fd 3 ไปยังไพพ์ไปยังกระบวนการที่ทำงานด้วย stdin ที่ปลายอีกด้านหนึ่งและ stdout จะไปที่ไพพ์ที่สร้างขึ้นก่อนหน้านี้ จากนั้นเราก็ปิดท้ายการเขียนของไพพ์นั้นในแม่ซึ่งเราไม่ต้องการ ตอนนี้ในเปลือกเรามี fd 3 เชื่อมต่อกับ stdin ของ cmd และ fd 4 เชื่อมต่อกับ stdout ของ cmd ด้วยท่อ

โปรดทราบว่าแฟล็ก close-on-exec ไม่ได้ถูกตั้งค่าไว้บนตัวให้คำอธิบายไฟล์เหล่านั้น

ในการดึงข้อมูล:

echo data >&3 4<&-

วิธีอ่านข้อมูล:

read var <&4 3>&-

และคุณสามารถปิด fds ได้ตามปกติ:

exec 3>&- 4<&-

ตอนนี้ทำไมพวกเขาถึงไม่ได้รับความนิยม

แทบจะไม่ได้รับประโยชน์ใด ๆ มากกว่าการใช้ท่อที่มีชื่อ

กระบวนการร่วมสามารถนำไปใช้กับท่อที่มีชื่อมาตรฐานได้อย่างง่ายดาย ฉันไม่รู้ว่าเมื่อไหร่ที่มีการเปิดตัวท่อชื่อ แต่เป็นไปได้ว่ามันkshเกิดขึ้นหลังจากมีกระบวนการร่วม (อาจจะอยู่ในช่วงกลางยุค 80, ksh88 ถูก "ปล่อย" ใน 88 แต่ฉันเชื่อว่าkshใช้ภายใน AT&T เมื่อไม่กี่ปีก่อน ที่) ซึ่งจะอธิบายว่าทำไม

cmd |&
echo data >&p
read var <&p

สามารถเขียนด้วย:

mkfifo in out

cmd <in >out &
exec 3> in 4< out
echo data >&3
read var <&4

การโต้ตอบกับสิ่งเหล่านั้นเป็นเรื่องที่ตรงไปตรงมามากขึ้นโดยเฉพาะถ้าคุณต้องการเรียกใช้กระบวนการร่วมมากกว่าหนึ่งกระบวนการ (ดูตัวอย่างด้านล่าง)

ประโยชน์เพียงอย่างเดียวของการใช้coprocคือคุณไม่ต้องล้างท่อที่มีชื่อหลังการใช้งาน

การหยุดชะงักได้ง่าย

หอยใช้ท่อในโครงสร้างไม่กี่:

  • ท่อเปลือก: cmd1 | cmd2 ,
  • การทดแทนคำสั่ง: $(cmd) ,
  • และกระบวนการทดแทน: <(cmd) , >(cmd).

ในนั้นข้อมูลไหลในทิศทางเดียวเท่านั้นระหว่างกระบวนการต่าง ๆ

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

ทำงานได้ไม่ดีไปกว่าexpectสิ่งที่ออกแบบมา

วัตถุประสงค์หลักของกระบวนการร่วมคือเพื่อให้เชลล์มีวิธีการโต้ตอบกับคำสั่ง อย่างไรก็ตามมันใช้งานไม่ได้

รูปแบบที่ง่ายที่สุดของการหยุดชะงักที่กล่าวถึงข้างต้นคือ:

tr a b |&
echo a >&p
read var<&p

เนื่องจากเอาต์พุตไม่ได้ไปที่เทอร์มินัลจึงtrบัฟเฟอร์เอาต์พุต ดังนั้นมันจะไม่แสดงผลใด ๆ จนกว่าจะเห็นจุดสิ้นสุดไฟล์ในstdinนั้นหรือมีการสะสมบัฟเฟอร์เต็มของข้อมูลเพื่อส่งออก ดังนั้นด้านบนหลังจากเชลล์มีเอาต์พุต a\n(เพียง 2 ไบต์) readจะบล็อกไม่สิ้นสุดเนื่องจากtrกำลังรอให้เชลล์ส่งข้อมูลเพิ่มเติม

กล่าวโดยย่อคือท่อไม่ดีสำหรับการโต้ตอบกับคำสั่ง กระบวนการร่วมสามารถใช้เพื่อโต้ตอบกับคำสั่งที่ไม่บัฟเฟอร์เอาต์พุตหรือคำสั่งที่สามารถบอกได้ว่าไม่บัฟเฟอร์ผลลัพธ์ ตัวอย่างเช่นโดยใช้stdbufกับคำสั่งบางอย่างในระบบ GNU หรือ FreeBSD ล่าสุด

นั่นเป็นเหตุผลexpectหรือzptyใช้เทอร์มินัลหลอกแทน expectเป็นเครื่องมือที่ออกแบบมาสำหรับการโต้ตอบกับคำสั่งและทำได้ดี

การจัดการไฟล์ descriptor เป็นเรื่องยุ่งและยากที่จะทำให้ถูกต้อง

กระบวนการร่วมสามารถใช้ในการทำประปาที่ซับซ้อนกว่าท่อเปลือกแบบง่ายๆ

คำตอบ Unix.SE อื่นนั้นมีตัวอย่างของการใช้ coproc

นี่คือตัวอย่างแบบง่าย:ลองนึกภาพว่าคุณต้องการฟังก์ชั่นที่ฟีดสำเนาของคำสั่งไปยัง 3 คำสั่งอื่น ๆ จากนั้นให้เอาท์พุทของ 3 คำสั่งเหล่านั้นมาต่อกัน

ทั้งหมดใช้ท่อ

ตัวอย่างเช่นอาหารการส่งออกของprintf '%s\n' foo barไปtr a b, sed 's/./&&/g'และcut -b2-เพื่อให้ได้สิ่งที่ต้องการ:

foo
bbr
ffoooo
bbaarr
oo
ar

ครั้งแรกมันไม่จำเป็นต้องชัดเจน แต่มีความเป็นไปได้สำหรับการหยุดชะงักที่นั่นและมันจะเริ่มเกิดขึ้นหลังจากข้อมูลเพียงไม่กี่กิโลไบต์

จากนั้นขึ้นอยู่กับเชลล์ของคุณคุณจะพบกับปัญหาที่แตกต่างกันจำนวนหนึ่งซึ่งต้องแก้ไขแตกต่างกัน

ตัวอย่างเช่นด้วยzshคุณจะทำกับ:

f() (
  coproc tr a b
  exec {o1}<&p {i1}>&p
  coproc sed 's/./&&/g' {i1}>&- {o1}<&-
  exec {o2}<&p {i2}>&p
  coproc cut -c2- {i1}>&- {o1}<&- {i2}>&- {o2}<&-
  tee /dev/fd/$i1 /dev/fd/$i2 >&p {o1}<&- {o2}<&- &
  exec cat /dev/fd/$o1 /dev/fd/$o2 - <&p {i1}>&- {i2}>&-
)
printf '%s\n' foo bar | f

ด้านบน fds ร่วมกระบวนการมีชุดแฟล็ก close-on-exec แต่ไม่ใช่แฟล็กที่ทำซ้ำจากพวกเขา (เหมือนใน{o1}<&p) ดังนั้นเพื่อหลีกเลี่ยงการหยุดชะงักคุณจะต้องตรวจสอบให้แน่ใจว่าปิดในกระบวนการใด ๆ ที่ไม่ต้องการ

ในทำนองเดียวกันเราต้องใช้ subshell และใช้exec catในท้ายที่สุดเพื่อให้แน่ใจว่าไม่มีกระบวนการเชลล์ที่โกหกเกี่ยวกับการเปิดท่อ

ด้วยksh(ที่นี่ksh93) นั่นจะต้องเป็น:

f() (
  tr a b |&
  exec {o1}<&p {i1}>&p
  sed 's/./&&/g' |&
  exec {o2}<&p {i2}>&p
  cut -c2- |&
  exec {o3}<&p {i3}>&p
  eval 'tee "/dev/fd/$i1" "/dev/fd/$i2"' >&"$i3" {i1}>&"$i1" {i2}>&"$i2" &
  eval 'exec cat "/dev/fd/$o1" "/dev/fd/$o2" -' <&"$o3" {o1}<&"$o1" {o2}<&"$o2"
)
printf '%s\n' foo bar | f

( หมายเหตุ:นั่นจะไม่ทำงานบนระบบที่kshใช้socketpairsแทนpipesและ/dev/fd/nทำงานได้บน Linux)

ในkshfds ด้านบน2ถูกทำเครื่องหมายด้วยแฟล็กclose-on-exec เว้นแต่ว่าพวกเขาจะถูกส่งผ่านอย่างชัดเจนในบรรทัดคำสั่ง นั่นเป็นเหตุผลที่เราไม่จำเป็นต้องปิดตัวอธิบายไฟล์ที่ไม่ได้ใช้เช่น - zshแต่มันก็เป็นสาเหตุที่เราต้องทำ{i1}>&$i1และใช้evalสำหรับค่าใหม่ของ$i1, จะถูกส่งผ่านไปteeและcat...

ในbashสิ่งนี้ไม่สามารถทำได้เพราะคุณไม่สามารถหลีกเลี่ยงการตั้งค่าสถานะ close-on-exec

ด้านบนมันค่อนข้างง่ายเพราะเราใช้คำสั่งภายนอกง่าย ๆ เท่านั้น มันซับซ้อนมากขึ้นเมื่อคุณต้องการใช้เชลล์สร้างในนั้นแทนและคุณเริ่มทำงานในเชลล์บั๊ก

เปรียบเทียบด้านบนด้วยการใช้ชื่อ pipes:

f() {
  mkfifo p{i,o}{1,2,3}
  tr a b < pi1 > po1 &
  sed 's/./&&/g' < pi2 > po2 &
  cut -c2- < pi3 > po3 &

  tee pi{1,2} > pi3 &
  cat po{1,2,3}
  rm -f p{i,o}{1,2,3}
}
printf '%s\n' foo bar | f

ข้อสรุป

หากคุณต้องการโต้ตอบกับคำสั่งใช้expectหรือzsh's zptyหรือไปป์ที่มีชื่อ

ถ้าคุณต้องการที่จะทำท่อประปาแฟนซีใช้ท่อชื่อ

กระบวนการร่วมสามารถทำสิ่งต่าง ๆ ข้างต้นได้ แต่ต้องเตรียมพร้อมที่จะทำอะไรบางอย่างที่ไม่สำคัญ


คำตอบที่ดีแน่นอน ฉันไม่รู้ว่าเมื่อใดที่มันถูกแก้ไขโดยเฉพาะ แต่อย่างน้อยตอนนี้bash 4.3.11คุณสามารถปิดตัวอธิบายไฟล์ coproc โดยตรงโดยไม่ต้องใช้ aux ตัวแปร; ในแง่ของตัวอย่างในคำตอบของคุณexec {tr[1]}<&- ตอนนี้จะทำงาน (เพื่อปิด stdin ของ coproc โปรดทราบว่ารหัสของคุณ (ทางอ้อม) พยายามที่จะปิดการ{tr[1]}ใช้>&-แต่{tr[1]}เป็นstdinของ coproc และจะต้องปิดด้วย<&-) การแก้ไขต้องมาจากที่ใดที่หนึ่ง4.2.25ซึ่งยังคงแสดงปัญหาและ4.3.11ที่ไม่ได้
mklement0

1
@ mklement0 ขอบคุณ exec {tr[1]}>&-ดูเหมือนจะทำงานกับเวอร์ชันที่ใหม่กว่าและมีการอ้างอิงในรายการ CWRU / changelog ( อนุญาตให้ใช้คำเช่น {array [ind]} เป็นการเปลี่ยนเส้นทางที่ถูกต้อง ... 2012-09-01) exec {tr[1]}<&-(หรือ>&-เทียบเท่าที่ถูกต้องมากขึ้นแม้ว่าจะไม่ได้สร้างความแตกต่างเหมือนที่เพิ่งเรียกclose()ทั้งคู่) ไม่ได้ปิด stroc ของ coproc แต่การเขียนปลายท่อไปที่ coproc นั้น
Stéphane Chazelas

1
@ mklement0 จุดดีฉันได้อัปเดตและเพิ่มyashแล้ว
Stéphane Chazelas

1
ข้อดีอย่างหนึ่งmkfifoคือคุณไม่ต้องกังวลเกี่ยวกับสภาพการแข่งขันและความปลอดภัยสำหรับการเข้าถึงท่อ คุณยังต้องกังวลเกี่ยวกับการหยุดชะงักของ Fifo
Otheus

1
เกี่ยวกับการหยุดชะงัก: stdbufคำสั่งสามารถช่วยป้องกันบางอย่างได้ ฉันใช้มันภายใต้ Linux และทุบตี อย่างไรก็ตามฉันเชื่อว่า @ StéphaneChazelasนั้นถูกต้องในบทสรุป: ขั้นตอน "การเกาหัว" จบลงสำหรับฉันเมื่อฉันเปลี่ยนกลับไปเป็นท่อที่มีชื่อเท่านั้น
shub

7

กระบวนการร่วมถูกนำมาใช้ครั้งแรกในภาษาสคริปต์เชลล์กับksh88เชลล์ (1988) และต่อมาในzshบางจุดก่อนปี 1993

ไวยากรณ์ที่จะเปิดตัวร่วมกระบวนการภายใต้ ksh command |&คือ เริ่มต้นจากนั้นคุณสามารถเขียนให้commandเข้ามาตรฐานด้วยและอ่านออกมาตรฐานด้วยprint -pread -p

กว่าสองสามทศวรรษต่อมาทุบตีซึ่งขาดคุณสมบัตินี้ในที่สุดก็เปิดตัวมันในรุ่น 4.0 ของมัน น่าเสียดายที่มีการเลือกไวยากรณ์ที่เข้ากันไม่ได้และซับซ้อนกว่า

ภายใต้ bash 4.0 และใหม่กว่าคุณสามารถเปิดใช้กระบวนการร่วมกับcoprocคำสั่งเช่น:

$ coproc awk '{print $2;fflush();}'

จากนั้นคุณสามารถส่งบางสิ่งไปยังคำสั่ง stdin ด้วยวิธีนี้:

$ echo one two three >&${COPROC[1]}

และอ่านผลลัพธ์ awk ด้วย:

$ read -ru ${COPROC[0]} foo
$ echo $foo
two

ภายใต้ ksh นั่นจะเป็น:

$ awk '{print $2;fflush();}' |&
$ print -p "one two three"
$ read -p foo
$ echo $foo
two

-1

"coproc" คืออะไร?

มันสั้นสำหรับ "กระบวนการร่วม" ซึ่งหมายถึงกระบวนการที่สองร่วมมือกับเชลล์ มันคล้ายกับงานพื้นหลังที่เริ่มต้นด้วย "&" ที่ส่วนท้ายของคำสั่งยกเว้นว่าแทนที่จะใช้อินพุตและเอาต์พุตมาตรฐานร่วมกันเป็นพาเรนต์เชลล์เดียวกันมาตรฐาน I / O มาตรฐานจะเชื่อมต่อกับพาเรนต์เชลล์โดยพิเศษ ชนิดของท่อที่เรียกว่า FIFO สำหรับการอ้างอิงคลิกที่นี่

หนึ่งเริ่ม coproc ใน zsh ด้วย

coproc command

คำสั่งจะต้องมีการเตรียมพร้อมที่จะอ่านจาก stdin และ / หรือเขียนไปยัง stdout หรือไม่ได้ใช้งานมากเท่า coproc

อ่านบทความนี้ที่นี่เป็นกรณีศึกษาระหว่าง exec และ coproc


คุณสามารถเพิ่มบทความลงในคำตอบของคุณได้ไหม? ฉันพยายามทำให้หัวข้อนี้ครอบคลุมใน U&L เนื่องจากดูเหมือนว่าจะเป็นตัวแทน ขอบคุณสำหรับคำตอบ! แจ้งให้ทราบด้วยฉันตั้งแท็กเป็น Bash ไม่ใช่ zsh
slm

@slm คุณได้ชี้ไปที่ Bash แฮ็กเกอร์แล้ว ฉันเห็นตัวอย่างเพียงพอ หากความตั้งใจของคุณคือการทำให้คำถามนี้ภายใต้ความสนใจแล้วใช่คุณประสบความสำเร็จ:>
Valentin Bajrami

|พวกเขากำลังชนิดไม่พิเศษของท่อที่พวกเขามีท่อเดียวกับที่ใช้กับ (นั่นคือใช้ไพพ์ในเชลล์ส่วนใหญ่และซ็อกเก็ตคู่ใน ksh93) ท่อและซ็อกเก็ตคู่เป็นแบบเข้าก่อนออกก่อนพวกเขาทั้งหมด FIFO mkfifoทำให้ไปป์ที่มีชื่อตัวประมวลผลร่วมไม่ใช้ไพพ์ที่มีชื่อ
Stéphane Chazelas

@slm ขอโทษสำหรับ zsh ... จริง ๆ แล้วฉันทำงานกับ zsh ฉันมักจะทำบางครั้งกับการไหล มันใช้งานได้ดีใน Bash เช่นกัน ...
Munai Das Udasin

@ Stephane Chazelas ฉันค่อนข้างแน่ใจว่าฉันอ่านมันที่ไหนสักแห่งที่มัน I / O เชื่อมต่อกับท่อชนิดพิเศษที่เรียกว่า FIFO ...
Munai Das Udasin

-1

นี่เป็นอีกตัวอย่างที่ดี (และใช้งานได้) - เซิร์ฟเวอร์อย่างง่ายที่เขียนด้วย BASH โปรดทราบว่าคุณต้องใช้ OpenBSD netcatคลาสสิกจะใช้งานไม่ได้ แน่นอนคุณสามารถใช้ซ็อกเก็ต inet แทน unix หนึ่ง

server.sh:

#!/usr/bin/env bash

SOCKET=server.sock
PIDFILE=server.pid

(
    exec </dev/null
    exec >/dev/null
    exec 2>/dev/null
    coproc SERVER {
        exec nc -l -k -U $SOCKET
    }
    echo $SERVER_PID > $PIDFILE
    {
        while read ; do
            echo "pong $REPLY"
        done
    } <&${SERVER[0]} >&${SERVER[1]}
    rm -f $PIDFILE
    rm -f $SOCKET
) &
disown $!

client.sh:

#!/usr/bin/env bash

SOCKET=server.sock

coproc CLIENT {
    exec nc -U $SOCKET
}

{
    echo "$@"
    read
} <&${CLIENT[0]} >&${CLIENT[1]}

echo $REPLY

การใช้งาน:

$ ./server.sh
$ ./client.sh ping
pong ping
$ ./client.sh 12345
pong 12345
$ kill $(cat server.pid)
$
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.