การวางท่อ STDERR กับ STDOUT


24

ตามที่ " ลินุกซ์: อ้างอิงสมบูรณ์ Edition 6 " (. หน้า 44) คุณสามารถท่อเท่านั้น STDERR โดยใช้|&สัญลักษณ์การเปลี่ยนเส้นทาง

ฉันได้เขียนสคริปต์เพื่อทดสอบสิ่งนี้:

#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2

ฉันรันสคริปต์นี้เช่นนี้:

./script.sh |& sed 's:^:\t:'

สันนิษฐานว่ามีเพียงบรรทัดที่พิมพ์ไปยัง STDERR เท่านั้นที่จะถูกเยื้อง อย่างไรก็ตามมันใช้งานไม่ได้จริง ๆ อย่างที่ฉันเห็น:

    Normal Text.
    Error Text. 

ฉันทำอะไรผิดที่นี่

คำตอบ:


26

ฉันไม่ทราบว่าหนังสือของคุณใช้ข้อความใด แต่คู่มือทุบตีชัดเจน (ถ้าคุณคุ้นเคยกับการเปลี่ยนเส้นทางไปบ้างแล้ว):

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

ดังนั้นหากคุณไม่ต้องการผสมเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐานคุณจะต้องเปลี่ยนเส้นทางเอาต์พุตมาตรฐานไปที่อื่น ดูวิธี grep สตรีมข้อผิดพลาดมาตรฐาน (stderr) ได้อย่างไร

{ ./script.sh 2>&1 >&3 | sed 's:^:\t:'; } 3>&1

ทั้ง fd 1 และ 3 ของscript.shและsedจะชี้ไปยังปลายทาง stdout ดั้งเดิมอย่างไรก็ตาม หากคุณต้องการเป็นพลเมืองที่ดีคุณสามารถปิด fd 3 ที่คำสั่งเหล่านั้นไม่ต้องการ:

{ ./script.sh 2>&1 >&3 3>&- | sed 's:^:\t:' 3>&-; } 3>&1

bashและksh93สามารถรวมตัว>&3 3>&-กับ>&3-(fd ย้าย)


คู่มือทุบตีไม่ชัดเจนสำหรับฉันเลย ผมไม่เข้าใจว่าทำไมค่อนข้างบเหมือน./script.sh > /tmp/stdout_goes_here |& grep 'grepping_script_stderr'ไม่ได้ทำงานตามที่ตั้งใจไว้คือ: การเปลี่ยนเส้นทางscript.sh's stdout(ซึ่งเป็นไปตามข้อมูลคู่มือควรจะเกิดขึ้นเป็นครั้งแรก) จากนั้นช่วยให้การประมวลผลของสคริปต์grep stderrแทนstderrและ tdout` ทั้งคู่จบลงด้วยstdout_goes_here
sxc731

1
@ sxc731 |&เป็น shorthard 2>&1 |สำหรับ ดังนั้น>/tmp/stdout_goes_here |&เปลี่ยนเส้นทาง stdout ไปที่/tmp/stdout_goes_hereจากนั้น2>&1เปลี่ยนเส้นทาง stderr ไปทุกที่ที่ stdout กำลังดำเนินการซึ่งก็คือ/tmp/stdout_goes_hereและในที่สุดก็|ไม่ได้รับอินพุตใด ๆ เพราะเอาต์พุตของคำสั่งถูกเปลี่ยนเส้นทาง โปรดทราบว่า>&1การเปลี่ยนเส้นทางไปที่ใดก็ตามที่ไฟล์อธิบาย 1 ในขณะนี้เป็นไปไม่ได้ที่จะที่ใดก็ตามที่ไฟล์อธิบาย 1 จะจบลงไป ท่อ stderr เท่านั้นและเปลี่ยนเส้นทาง stdout 2>&1 >/tmp/stdout_goes_here |ไปยังแฟ้มวิธีหนึ่งคือ
Gilles 'หยุดความชั่วร้าย'

6

|&pipes stderr ถึง stdin เช่น2>&1 |นั้นโปรแกรมถัดไปจะได้รับทั้งคู่ใน stdin

$cat test.sh
#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2
$./test.sh | sed 's:^:\t:'
Error Text.
        Normal Text.
$ ./test.sh |& sed 's:^:\t:'
        Normal Text.
        Error Text.

โอ้โดยพื้นฐานแล้วมันเทียบเท่ากับนิพจน์ที่ยาวกว่านี้runcommand 2>&1 | teeไหม คือruncommand |& teeอะไร
Naftuli Kay

ใช่พวกเขาเหมือนกัน
เควิน

1

|&ใน bash เป็นเพียงช็อตคัต (ไม่ใช่พกพาได้ดีมาก) 2>&1 |ดังนั้นคุณควรเห็นการเยื้องทุกบรรทัด

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