ท่อกึ่งอะซิงโครนัส


11

สมมติว่าฉันมีท่อต่อไปนี้:

a | b | c | d

ฉันจะรอให้เสร็จสิ้นการc(หรือb) ในshหรือbash? ซึ่งหมายความว่าสคริปต์dสามารถเริ่มต้นได้ตลอดเวลา (และไม่จำเป็นต้องรอ) แต่ต้องการเอาต์พุตที่สมบูรณ์จากcการทำงานอย่างถูกต้อง

กรณีการใช้งานมีdifftoolไว้สำหรับgitเปรียบเทียบรูปภาพ มันถูกเรียกใช้โดยgitและต้องการประมวลผลอินพุต ( a | b | cส่วน) และแสดงผลลัพธ์ของการเปรียบเทียบ ( dส่วน) โทรจะลบการป้อนข้อมูลที่จำเป็นสำหรับการและa bซึ่งหมายความว่าก่อนที่จะส่งคืนจากสคริปต์กระบวนการc(หรือb) จะต้องยุติ ในทางกลับกันฉันไม่สามารถรอได้dเพราะนี่หมายความว่าฉันกำลังรอการป้อนข้อมูลจากผู้ใช้

ฉันรู้ว่าฉันสามารถเขียนผลของการcไปยังแฟ้มชั่วคราวหรืออาจจะใช้ FIFO bashใน (ไม่แน่ใจว่า FIFO จะช่วยได้หรือไม่) เป็นไปได้ไหมหากไม่มีไฟล์ชั่วคราวsh?

แก้ไข

อาจจะเพียงพอหากฉันสามารถหา ID กระบวนการของกระบวนการc(หรือb) ในแบบที่เชื่อถือได้ จากนั้นไพพ์ทั้งหมดสามารถเริ่มต้นแบบอะซิงโครนัสได้และฉันอาจรอรหัสกระบวนการ บางสิ่งบางอย่างตามแนวของ

wait $(a | b | { c & [print PID of c] ; } | d)

แก้ไข ^ 2

ฉันได้พบวิธีแก้ไขปัญหาความคิดเห็น (หรือยังดีกว่าโซลูชัน) ยินดีต้อนรับ


คุณหมายถึงคุณต้องการที่dจะเริ่มการประมวลผลcหลังจากcเสร็จสิ้นแล้วหรือไม่ คุณไม่ต้องการที่dจะเริ่มการประมวลผลแต่ละบรรทัดออกมา?
terdon

@terdon: ไม่dสามารถเริ่มได้ฟรีทุกครั้งที่มันชอบ แต่cต้องทำให้เสร็จก่อนที่ฉันจะสามารถเดินหน้าต่อไปได้
krlmlr

ดูเหมือนว่าจะขัดแย้งตัวเองถ้าdสามารถเริ่มได้เมื่อมันชอบคุณจะรออะไรอยู่?
terdon

@terdon: ขยายเพื่อแสดงกรณีการใช้งาน
krlmlr

หากdไม่ได้ใช้ผลลัพธ์ของcมันก็ดูเหมือนจะไม่เหมาะสมที่จะdเป็นส่วนหนึ่งของไปป์ไลน์ แต่ถ้าdใช้อินพุตคุณdจะต้องใช้เวลาสักครู่ในการป้อนข้อมูลหลังจากอ่านทั้งหมดเพื่อให้แนวทางของคุณสร้างความแตกต่าง
Hauke ​​Laging

คำตอบ:


6
a | b | { c; [notify];} | d

การแจ้งเตือนสามารถทำได้เช่นโดยสัญญาณไปยัง PID ซึ่งผ่านไปแล้วในตัวแปรสภาพแวดล้อม ( kill -USR1 $EXTPID) หรือโดยการสร้างไฟล์ ( touch /path/to/file)

ความคิดอื่น:

คุณดำเนินการกระบวนการถัดไป (กระบวนการที่จะเริ่มต้นคุณกำลังรอ) จากไปป์ไลน์:

a | b | { c; exec >&-; nextprocess;} | d

หรือ

a | b | { c; exec >&-; nextprocess &} | d

ขอบคุณ แต่จากนั้นการสร้างไฟล์ชั่วคราวสำหรับเอาท์พุทระดับกลางนั้นมีความละเอียดมากขึ้นและง่ายต่อการแยกวิเคราะห์ (สำหรับคน) นอกจากนี้ฉันจะหลีกเลี่ยงสภาพการแข่งขันด้วยสัญญาณได้อย่างไร ... ฉันหวังว่าจะได้คำตอบที่สะอาดกว่านี้ แต่ถ้าเป็นไปได้
krlmlr

@krlmlr สภาพการแข่งขันเป็นอย่างไร?
Hauke ​​Laging

notifyสามารถดำเนินการได้ก่อนที่ฉันจะตั้งค่ากับดักสัญญาณ ฉันจะแน่ใจได้อย่างไรว่าไม่พลาดสัญญาณนั้น?
krlmlr

@krlmlr คุณหยุดสคริปต์ที่เรียกไปป์ไลน์จนกว่าจะได้รับสัญญาณซึ่งถูกส่งหลังจากที่trapกำหนดแล้ว
Hauke ​​Laging

การแก้ไขของคุณ: ไปป์ถูกเรียกเป็นวนซ้ำซึ่งฉันไม่สามารถควบคุมได้ น่าเสียดาย{ c; bg; }หรือ{ c; exit 0; }ดูเหมือนจะไม่ทำงาน
krlmlr

5

หากฉันเข้าใจคำถามของคุณถูกต้องสิ่งนี้ควรจะได้ผล:

a | b | c | { (exec <&3 3<&-; d) &} 3<&0

(เคล็ดลับ fd 3 เป็นเพราะเชลล์ (ส่วนใหญ่) เปลี่ยนเส้นทาง stdin ไปยัง / dev / null ด้วย&)


4

ในทุบตีคุณสามารถใช้ทดแทนกระบวนการ คำสั่งในการทดแทนกระบวนการทำงานแบบอะซิงโครนัสไม่รอ

a | b | c > >(d)

ขอบคุณ นี่เป็นbashเพียงใช่ไม่มีshการสนับสนุน?
krlmlr

@krlmlr Bash / zsh เท่านั้น (และ ksh93 ที่มีการแก้ไขเล็กน้อย)
Gilles 'หยุดชั่วร้าย'

3

นี่คือสิ่งที่ฉันได้พบโดยการลองผิดลองถูกด้วยความช่วยเหลือจากอินพุตของ Hauke:

a | b | { c; kill -PIPE $$; } | d

เท่า:

a | b | ( c; kill -PIPE $$; ) | d

(หลังมีความชัดเจนมากขึ้นเพราะ{}จะทำงานใน subshell ต่อไปหากภายในท่อ)

บางสัญญาณอื่น ๆ (รวมทั้งQUIT, TERMและUSR1) การทำงานมากเกินไป แต่ในกรณีนี้คำอธิบายของสัญญาณที่จะปรากฏบนสถานี

ฉันสงสัยว่านี่เป็นความตั้งใจดั้งเดิมของPIPEสัญญาณหรือไม่ ตามคู่มือ :

SIGPIPE: PIPEสัญญาณจะถูกส่งไปยังกระบวนการเมื่อพยายามเขียนไปยังไพพ์โดยไม่มีกระบวนการเชื่อมต่อกับปลายอีกด้าน

ซึ่งหมายความว่าเมื่อฉันส่งสัญญาณไพพ์ไปยัง subshell อย่างตั้งใจมันก็จะเงียบลงและทำให้ผู้ใช้ขั้นสุดท้าย ( d) อยู่คนเดียว

งานนี้ทั้งในและshbash


0

คุณสามารถใช้spongeโปรแกรมจากแพ็คเกจ "moreutils":

a | b | c | sponge | d

ฟองน้ำประสงค์สำหรับการสิ้นสุดของc's dผลผลิตก่อนที่ท่อมัน หวังว่าเป็นสิ่งที่คุณต้องการ


0

คุณสามารถทำได้:

a | b | c | (d ; cat > /dev/null)

ดังนั้นเมื่อdเสร็จแล้วcatจะดูดซับcเอาท์พุทที่เหลือจนกว่ามันจะเสร็จ

ตกลง. หลังจากความคิดเห็นฉันคิดว่าคำตอบคือการเริ่มต้นโดยตรงdในพื้นหลัง

ทำ:

a | b | c | (d &)

หรือใช้สเตฟาน Chazelasแก้ปัญหา 's ถ้ามีปัญหากับdการอ่านจากstdin


ผมเกรงว่ากรณีการใช้งานของฉันค่อนข้างรอบวิธีอื่น ๆ : cเสร็จสิ้นก่อนหน้านี้กว่าdและผมต้องรอจนกว่าจะcเสร็จสิ้น dแต่ไม่ดูแล
krlmlr

ขอโทษฉันไม่เข้าใจ คุณต้องการทำอะไรเมื่อcเสร็จสิ้นและdยังทำงานอยู่ ฆ่าdเหรอ
กัส

dมี GUI และสามารถทำงานได้จนกว่าผู้ใช้จะปิด
krlmlr

ตกลง ... แต่นี่เกิดขึ้นแล้ว เมื่อa, bและcเสร็จสิ้นการทำงานของพวกเขาอย่างใกล้ชิดและ stdout ทางออก; และdยังคงทำงานอยู่เท่านั้น คุณต้องการที่จะส่งdไปที่พื้นหลังเมื่อcเสร็จสิ้น? มันคืออะไร
กัส

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