ด้วยการทุบตีฉันจะท่อข้อผิดพลาดมาตรฐานไปยังกระบวนการอื่นได้อย่างไร


140

เป็นที่ทราบกันดีว่าจะวางท่อส่งออกมาตรฐานของกระบวนการไปยังอินพุตมาตรฐานอื่นของกระบวนการได้อย่างไร:

proc1 | proc2

แต่ถ้าฉันต้องการส่งข้อผิดพลาดมาตรฐานของ proc1 ไปยัง proc2 และปล่อยให้เอาต์พุตมาตรฐานไปยังตำแหน่งปัจจุบัน คุณคิดว่าbashจะมีคำสั่งตามบรรทัดของ:

proc1 2| proc2

แต่อนิจจาไม่ มีวิธีใดบ้างที่จะทำเช่นนี้?


คุณสามารถเปลี่ยนเส้นทางง่ายๆในrcซึ่งเป็นเชลล์อื่น เช่น: proc1 |[2] proc2. ไม่ดีเหรอ? ไม่ได้อยู่ในbashนั้น
Rolf

คำตอบ:


173

นอกจากนี้ยังมีการทดแทนกระบวนการ ซึ่งทำให้กระบวนการแทนที่ไฟล์
คุณสามารถส่งstderrไปยังไฟล์ได้ดังนี้:

process1 2> file

แต่คุณสามารถแทนที่กระบวนการสำหรับไฟล์ได้ดังนี้:

process1 2> >(process2)

นี่คือตัวอย่างที่เป็นรูปธรรมที่ส่งstderrไปยังทั้งหน้าจอและต่อท้ายไฟล์บันทึก

sh myscript 2> >(tee -a errlog)

24
สิ่งนี้ตอบคำถามที่ระบุได้อย่างถูกต้องและควรเป็นคำตอบที่ยอมรับโดย @paxdiablo
mmlb

ฉันลองสิ่งนี้แล้ว มันไม่ได้ผล ( weston --help 2> >(less)) และมันทำให้เปลือกของฉันแตกฉันต้องออกและกลับเข้าสู่ระบบอีกครั้ง
Rolf

1
@Rolf หากทั้งคู่weston --helpและlessคาดหวังว่าจะมีการโต้ตอบกับแป้นพิมพ์ แต่มีเพียง 1 คนเท่านั้นที่ได้รับมันคุณอาจตกอยู่ในสถานการณ์ที่น่าอึดอัดใจ ลองทำการทดสอบด้วยสิ่งที่ชอบgrepแทน นอกจากนี้คุณอาจพบว่าอินพุตเมาส์ / คีย์บอร์ดทั้งสองจะไปที่คำสั่งที่ 2 ต่อไปแทนที่จะเป็นเวสตัน
BeowulfNode42

หากคุณต้องการเปลี่ยนเส้นทางทั้งการใช้ stderr และ stdout |&ฉันเรียนรู้จากที่นี่
ᐅ devrimbaris

88

คุณสามารถใช้เคล็ดลับต่อไปนี้เพื่อแลกเปลี่ยน และstdout stderrจากนั้นคุณก็ใช้ฟังก์ชันท่อปกติ

( proc1 3>&1 1>&2- 2>&3- ) | proc2

ให้stdoutและstderrทั้งสองชี้ไปที่จุดเริ่มต้นสิ่งนี้จะให้สิ่งที่คุณต้องการ

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

  • 3>&1สร้างหมายเลขอ้างอิงใหม่3ซึ่งจะส่งออกไปยังหมายเลขอ้างอิงปัจจุบัน1 (stdout เดิม) เพียงเพื่อบันทึกไว้ที่ใดที่หนึ่งสำหรับสัญลักษณ์แสดงหัวข้อย่อยสุดท้ายด้านล่าง
  • 1>&2แก้ไขหมายเลขอ้างอิง1(stdout) เพื่อส่งออกไปยังหมายเลขอ้างอิงปัจจุบัน2 (stderr เดิม)
  • 2>&3-แก้ไขหมายเลขอ้างอิง2(stderr) เพื่อส่งออกไปยังหมายเลขอ้างอิงปัจจุบัน3 (stdout เดิม) จากนั้นปิดที่จับ3(ผ่านทาง-ด้านท้าย)

เป็นคำสั่ง swap ที่คุณเห็นในอัลกอริทึมการเรียงลำดับอย่างมีประสิทธิภาพ:

temp   = value1;
value1 = value2;
value2 = temp;

3
อะไรคือคุณค่าของการใช้1>&2-ที่นี่มากกว่าแค่1>&2? ฉันไม่เข้าใจว่าทำไมเราถึงต้องการปิด fd 2ถ้าเราจะเปิดใหม่ / กำหนดใหม่ทันที
พิรุธจิม

1
@dubiousjim ไม่มีข้อได้เปรียบในกรณีนั้นฉันสงสัยว่าฉันทำเพื่อให้สอดคล้องกัน - การปิด file handle 3 เป็นความคิดที่ดีที่จะทำให้มันว่าง
paxdiablo

จุดดี @ovgolovin ฉันไม่อยากเชื่อเลยว่าจะไม่มีใครเลือกสิ่งนั้นในเจ็ดเดือนนับตั้งแต่ฉันทำการแก้ไข แก้ไขตามคำแนะนำของคุณ
paxdiablo

พยายามทำให้ gcc (ซึ่งเป็นสีในระบบของฉัน) เพื่อทำงานกับสิ่งนี้ "(make 3> & 1 1> & 2- 2> & 3-) | less -R" while "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "ทำงานตามที่คาดไว้
ไนซ์

ดูเหมือนว่าคำอธิบายของคุณจะกลับไปข้างหน้าสำหรับการเปลี่ยนเส้นทางสองครั้งที่สอง 1> & 2- ตั้งค่า file handle 2 (stderr ดั้งเดิม) เพื่อจัดการ 1 (stdout ดั้งเดิม) 2> & 3- ตั้งค่า file handle 3 (stdout ที่คัดลอก) เพื่อจัดการ 2 (stderr ดั้งเดิม) โปรดแก้ไขฉันถ้าฉันผิด btw ฉันเดาว่าเส้นประบน 2 คือเพื่อป้องกันไม่ให้ข้อมูล stderr ใหม่ถูกส่งไปยังบัฟเฟอร์นี้ในขณะที่มีการเติมข้อมูลจาก stdout
aghsmith

71

Bash 4 มีคุณสมบัตินี้:

ถ้าใช้ `| & 'ข้อผิดพลาดมาตรฐานของ command1 จะเชื่อมต่อกับอินพุตมาตรฐานของ command2 ผ่านท่อ เป็นชวเลขสำหรับ 2> & 1 |. การเปลี่ยนเส้นทางโดยนัยของข้อผิดพลาดมาตรฐานนี้ดำเนินการหลังจากการเปลี่ยนเส้นทางใด ๆ ที่ระบุโดยคำสั่ง

zsh ยังมีคุณสมบัตินี้

-

กับเชลล์อื่น ๆ / เก่ากว่าให้ป้อนสิ่งนี้อย่างชัดเจนเป็น

FirstCommand 2> & 1 | อื่น ๆ


14
จากการอ่านเอกสารจะมีทั้งข้อผิดพลาดมาตรฐานและเอาต์พุตซึ่งต่างจาก stderr แต่ก็ยินดีที่ได้ทราบ เวลาเริ่มดู bash 4 ฉันคิดว่า
paxdiablo

คู่มือ bash ปัจจุบันอ่านว่า "ถ้า | & ถูกใช้แล้วข้อผิดพลาดมาตรฐานของคำสั่ง นอกเหนือจากเอาต์พุตมาตรฐานจะเชื่อมต่อกับอินพุตมาตรฐานของ command2" นี่ไม่ใช่สิ่งที่ OP ต้องการอย่างชัดเจน
Peter - คืนสถานะ Monica

@ PeterA.Schneider: OP ระบุว่า "ปล่อยเอาต์พุตมาตรฐานไปยังตำแหน่งปัจจุบัน" ซึ่งอาจคลุมเครือ
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

ฉันไม่เห็นความคลุมเครือใด ๆ ข้อเสนอแนะของคุณ (1) ทำให้สองสตรีมรวมกัน (2) OtherCommandเขียนข้อมูลที่รวมไว้ที่ใดที่หนึ่งอาจเป็นที่อื่น ดังนั้นจึงไม่ใช่ข้อมูลเดียวกันและอาจไปที่อื่นได้ นั่นมันตรงข้ามกับความปรารถนาของ OP ไม่ใช่เหรอ?
Peter - คืนสถานะ Monica

@ PeterA.Schneider: ตำแหน่งปัจจุบันของเอาต์พุตมาตรฐานอยู่ที่ไหน หากproc1เอาต์พุตเป็น stdout และไปยัง stderr และคุณต้องการให้ stderr ไปที่ stdin ของproc2(ซึ่งเป็นที่ที่ stdout ของ proc1 กำลังไป) คำตอบของฉันก็สำเร็จ ฉันให้ OP สิ่งที่เขาถามหาบางทีอาจจะไม่ใช่สิ่งที่เขาหมายถึงการที่จะขอ ในนั้นมีความคลุมเครือที่อาจเกิดขึ้น OP ยอมรับคำตอบซึ่งแลกเปลี่ยน stdout และ stderr ซึ่งไม่ใช่สิ่งที่เขาขอ
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

28

การแลกเปลี่ยนเป็นสิ่งที่ดีเนื่องจากช่วยแก้ปัญหาได้ ในกรณีที่คุณไม่ต้องการแม้แต่ stdout ดั้งเดิมคุณสามารถทำได้ด้วยวิธีนี้:

proc1 2>&1 1>/dev/null | proc2

คำสั่งมีความสำคัญ คุณไม่ต้องการ:

proc1 >/dev/null 2>&1 | proc1

เพราะจะเปลี่ยนเส้นทางไปที่/dev/null!


0

สิ่งเหล่านี้ไม่ได้ผลดีมาก วิธีที่ดีที่สุดที่ฉันพบว่าทำในสิ่งที่คุณต้องการคือ:

(command < input > output) 2>&1 | less

ใช้งานได้เฉพาะในกรณีที่commandไม่จำเป็นต้องป้อนแป้นพิมพ์ เช่น:

(gzip -d < file.gz > file) 2>&1 | less

จะทำให้ข้อผิดพลาด gzip น้อยลง

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