ท่อ B ถึง D? - A&& B || C | D


14

มีวิธีการเขียนโครงสร้างคำสั่งอีกครั้งA && B || C | Dเพื่อให้ B หรือ C ถูกไพพ์ลงใน D หรือไม่?

ด้วยคำสั่งปัจจุบันเพียง B หรือทั้ง C และ D จะทำงาน

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

ป้อนคำอธิบายรูปภาพที่นี่

คำตอบ:


31

ใช่ในทุบตีคุณสามารถใช้วงเล็บ:

(A && B || C) | D

วิธีนี้การส่งออกของจะได้รับการประปาเข้าA && B || CD


6
หรือA && (B || C) | Dหากคุณไม่ต้องการให้ B, C หรือ D ทำงานเมื่อ A ล้มเหลว
zwol

2
คุณสามารถใช้ parens ในsh:)
EKons

ไม่ชัดเจนว่าการใช้วงเล็บแทนการจัดฟันแบบโค้งเป็นการตัดสินใจโดยเจตนา (ถ้าเป็นเช่นนั้นมีประโยชน์อะไรบ้าง) หรือการกำกับดูแล คุณอธิบายได้ไหม
Tom Fenech

@TomFenech Parens ทำให้นิพจน์ทำงานใน sub-shell ซึ่งเป็นกระบวนการแยก (เดี่ยว) จาก POV ของส่วนที่เหลือของสคริปต์ ดังนั้นไม่ว่าเอาต์พุตของนิพจน์ภายใน parens จะถูกไพพ์ด้วยกัน (ตั้งแต่Aอยู่ภายใน subshell นี้ยังรวมถึงA.)
jpaugh

1
@ jpaugh ฉันคิดว่าจุดของคุณเกี่ยวกับความโดดเดี่ยวนั้นเป็นสิ่งที่ดี แต่การส่งออกจะเป็นไปในลักษณะเดียวกันเมื่อใช้วงเล็บปีกกาใช่ไหม?
Tom Fenech

14

คุณสามารถเขียนสิ่งนี้เป็น

if A; then B; else C; fi | D

คุณบอกว่าคุณต้องการที่จะทำงานอย่างใดอย่างหนึ่งBหรือCแต่A && B || Cไม่ประสบความสำเร็จ หากAประสบความสำเร็จ แต่วิ่งและล้มเหลวก็จะดำเนินการBC

หมายเหตุ 1: หากคุณสามารถรับประกันได้ว่าBจะประสบความสำเร็จและต้องการติดอยู่กับรุ่นสั้น ๆ อยู่เสมอฉันก็ยังคงเลือกใช้

{ A && B || C; } | D

ใน( ... )ขณะที่หลังบังคับให้สร้างเชลล์ย่อยใหม่โดยไม่จำเป็นซึ่งอาจหรือไม่ได้รับการปรับให้เหมาะสม

หมายเหตุ 2: ทั้งสองรูปแบบสมมติว่าAไม่มีผลผลิตซึ่งเป็นจริงในตัวอย่างของคุณ แต่ไม่จำเป็นต้องเป็นเช่นนั้นโดยทั่วไป ที่สามารถหลีกเลี่ยงได้ด้วย

A; if [ "$?" -eq 0 ]; then B; else C; fi | D

คุณแน่ใจหรือ{ … }ไม่ว่าไม่บังคับให้สร้างเชลล์ย่อยเนื่องจากไปป์ ผมสังเกตพฤติกรรมต่อไปนี้: pgrep bashและpgrep bash | catและif true; then pgrep bash; fiและ{ pgrep bash; }มีเส้นหนึ่งของการส่งออก; ( pgrep bash; )และ( pgrep bash; ) | catและ{ pgrep bash; } | catและif true; then pgrep bash; fi | catมีเอาต์พุตสองบรรทัด
wchargin

@wchargin ... | ...เป็นสาเหตุให้สร้างเชลล์ย่อยซึ่งไม่สามารถหลีกเลี่ยงได้ ( ... )อย่างน้อยในทางทฤษฎีทำให้เกิดการสร้างsubshell เพิ่มเติมเพื่อ{ ...; }หลีกเลี่ยง แต่นั่นคือสิ่งที่ฉันหมายถึงด้วย "อาจหรืออาจไม่ได้รับการปรับปรุงให้ดีที่สุด": เป็นไปได้ว่าในกรณีนี้เชลล์รู้ตัวว่ามันไม่สำคัญ ผลกระทบจะเหมือนกัน
hvd

5

คำตอบยินดีรับถูกต้อง แต่ก็ไม่ได้ครอบคลุมถึงกรณีการใช้งานที่มีศักยภาพที่จะไม่ได้มีการส่งออกของAเป็น input Dของ เพื่อให้บรรลุว่าคุณจะต้องมีการเปลี่ยนเส้นทางสตรีมAขึ้นอยู่กับความต้องการของคุณ

  • หากคุณต้องการยกเลิกผลลัพธ์ของAอย่างไรก็ตาม:

    { A >/dev/null && B || C; } | D
  • หากคุณต้องการเห็นผลลัพธ์ของAบนเทอร์มินัล:

    { A >/dev/tty && B || C; } | D
  • หากคุณต้องการผลลัพธ์Aเป็นอินพุตของคำสั่งต่อมาEคุณจะต้องมีกลุ่มคำสั่งเพิ่มเติมและการเปลี่ยนเส้นทางสตรีม:

    { { A >&3 && B || C; } | D; } 3>&1 | E

หากทั้งหมดนี้ดูลึกลับเกินไปสำหรับคุณ (เช่นเดียวกับฉัน) ฉันขอแนะนำให้คุณใช้ตัวแปรเชลล์พิเศษสำหรับสถานะทางออกAและทำงานกับมัน:

A
if [ $? -eq 0 ]; then
  B
else
  C
fi |
D

ถ้าคุณต้องการที่จะกระชับมากกว่า แต่ไม่ลึกลับเกินไปฉันแนะนำสิ่งนี้:

A; { [ $? -eq 0 ] && B || C; } | D

(ดูส่วนสุดท้ายของคำตอบของ hvdซึ่งฉันไม่ได้สังเกตเมื่อฉันเขียนคำตอบดั้งเดิม)


คำตอบของฉันครอบคลุมที่ ดูสิ่งที่ฉันใส่ไว้ใน "หมายเหตุ 2:" ซึ่งฉันเพิ่งย้ายAออกจากท่อ
hvd

@hvd: คุณถูกต้องและขอบคุณที่ชี้ให้เห็นส่วนหนึ่งของคำตอบของคุณกับฉัน! ฉันแก้ไขการอ้างสิทธิ์ของฉันและให้เครดิตคุณตามนั้น
David Foerster
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.