จะทราบได้อย่างไรว่าเอาต์พุตของคำสั่งหรือเชลล์สคริปต์คือ stdout หรือ stderr


32

ให้เราบอกว่าฉันเรียกใช้คำสั่งหรือสคริปต์เปลือกและมันทำให้ฉันออก โดยไม่ทราบว่าภายในของคำสั่งนี้หรือเชลล์สคริปต์หนึ่งจะกำหนดได้อย่างไรว่าเป็นผลมาจากstderrหรือstdout?

สำหรับเช่น

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

VS

ls -ld /test
ls: /test: No such file or directory

ฉันจะแน่ใจได้อย่างไรว่าคำสั่งแรกที่พิมพ์ไปยังstdoutและที่สองที่จะstderr(มันได้หรือไม่)?


1
คุณพยายามแก้ไขปัญหาอะไรที่นี่
Kenster

3
กลัวว่าจะมีคนถามว่า ไม่มีจริง ๆ ส่วนใหญ่อยากรู้อยากเห็นและหวังว่าจะปรับปรุงความเข้าใจของฉันจากการเปลี่ยนเส้นทาง
กม.

7
คุณสามารถใส่stderredในสภาพแวดล้อมของเปลือกของคุณLD_PRELOADที่จะได้รับstdoutและstderrในสีที่แตกต่างกัน นี่คือคำถามที่เกี่ยวข้องในหลอดเลือดดำนั้น
Anko

คำตอบ:


18

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

สิ่งที่คุณสามารถทำได้ในกรณีเช่นข้างต้นคือการเรียกใช้คำสั่งด้วยstdoutและstderrเปลี่ยนเส้นทางไปยังสถานที่ต่าง ๆ และดูว่าเกิดอะไรขึ้น หรือเรียกใช้สองครั้งครั้งเดียวโดยstdoutเปลี่ยนเส้นทางไปยัง/dev/nullและอีกครั้งด้วยการstderrเปลี่ยนเส้นทางไปที่/dev/nullและดูว่ากรณีใดที่ทำให้เกิดข้อความปรากฏขึ้น

คุณสามารถเปลี่ยนเส้นทางstdoutไป/dev/nullโดยตรึง>/dev/nullบนจุดสิ้นสุดของบรรทัดคำสั่งและคุณสามารถเปลี่ยนเส้นทางstderrไปโดยการเพิ่ม/dev/null2>/dev/null


9

คุณสามารถเปลี่ยนเส้นทาง stdout ใช้> fileและ stderr 2> fileเปลี่ยนเส้นทางโดยใช้ เชลล์สมัยใหม่จำนวนมากรองรับการเปลี่ยนเส้นทางไปยังคำสั่งดังนั้นคุณสามารถใช้sedเพื่อเน้นว่าเอาต์พุตใดมาจากสตรีมใด:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

ดีมาก! มันจะดีมากถ้าใครสามารถเน้นสีเป็นเส้นแทนที่จะเป็นคำนำหน้า
dotancohen

3
@dotancohen: หนึ่งทำได้! เช่น(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
PM 2Ring

โปรดทราบว่าหากมีเอาต์พุตผสมจาก stdout และ stderr stdout แรกจะถูกพิมพ์จากนั้น stderr
nyuszika7h

5

annotate-outputสคริปต์จาก Debian ของdevscriptsช่วยให้คุณทำเช่นนี้การคัดเลือก:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

คอลัมน์ที่สองระบุ stdout และ stderr ด้วยOและEตามลำดับ

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

วิธีนี้ใช้ Fifos การเขียนไปที่ Fifo สามารถทำงานได้แตกต่างจากการเขียนไปยัง tty และการเขียนถึง Fifos ที่แตกต่างกันสองอย่างนั้นแตกต่างกันอย่างแน่นอน นอกจากนี้ยังไม่เหมาะสำหรับการใช้เชิงโต้ตอบเช่นannotate-output bashไม่ใช่แผนการที่ยอดเยี่ยม แต่มีประโยชน์สำหรับวัตถุประสงค์อื่น ๆ มีตัวอย่างสคริปต์และฟังก์ชันเชลล์จำนวนมากในการตอบคำถามที่เกี่ยวข้องเกี่ยวกับ colorising stdin / stdout / stderr ที่แข็งแกร่งที่สุดคือstderrdซึ่งใช้การแก้ไขรันไทม์ของโปรแกรม (ส่วนใหญ่) เพื่อแก้ไขข้อมูลที่เขียนไปยัง stderr

คำถามนี้ที่ Anko เชื่อมโยงไปยังมีคำตอบที่ดีเกี่ยวกับชุดรูปแบบที่เกี่ยวข้อง: colorizing ผลลัพธ์ stdout / stderr: ฉันสามารถกำหนดค่าเปลือกของฉันเพื่อพิมพ์ STDERR และ STDOUT ในสีที่ต่างกันได้หรือไม่?


1
โปรดทราบว่ามันเป็นbashสคริปต์ที่ใช้while readลูปและรันหนึ่งdateคำสั่งสำหรับแต่ละบรรทัดของ stdout หรือ stderr ดังนั้นมันจะมีประสิทธิภาพน้อยกว่าที่cmd > >(ts '%T O:') 2> >(ts '%T E:')เทียบเท่า
Stéphane Chazelas

1

นอกเหนือจากคำตอบอื่น ๆ มันก็หยุดที่จะชี้ไปที่/proc/$PID/fd(แม้ว่ามันจะไม่ตอบคำถาม):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

อย่างที่คุณเห็นที่นี่คุณสามารถเห็นตัวอธิบายไฟล์ที่เปิดสำหรับกระบวนการ 0เป็นSTDIN, 1เป็นSTDOUTและเป็น2 STDERRหากคุณไม่ได้เปลี่ยนเส้นทาง STDOUT หรือ STDERR คุณจะเห็น/dev/pts/33(ในตัวอย่างนี้เป็นอย่างน้อย) เพราะพวกเขาจะชี้ไปที่เทอร์มินัล

หมายเหตุ : /proc/$PIDมีอยู่สำหรับกระบวนการทำงานเท่านั้น ในกรณีนี้ผมได้ใช้โดยไม่ขัดแย้งจึงไม่จบจนกว่าฉันจะปิดcat STDINฉันได้ดำเนินการในพื้นหลังดังนั้นฉันมี PID ทันทีเพื่อประโยชน์ของตัวอย่างนี้


0

ไม่ชัดเจนว่าคุณถามอะไร แต่อาจช่วยได้

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

แหล่ง

หากรหัสทางออกคือ 0 หมายความว่าคำสั่งนั้นดำเนินการอย่างถูกต้อง (stdout) ที่นี่คุณสามารถค้นหาความหมายได้หากรหัสทางออกแตกต่างจาก 0 (stderr)


น่าสนใจมาก! ฉันจะไม่เชื่อมต่อสถานะทางออกด้วยการเปลี่ยนเส้นทาง ศูนย์หมายถึงstdoutและไม่เป็นศูนย์หมายถึงstderrหรือไม่
กม.

7
@KM. ไม่ ฉันจะบอกว่ามันมีความสัมพันธ์กันอย่างมาก แต่ไม่มีอะไรที่จะหยุดโปรแกรมไม่ให้เขียนstderrและส่งคืนรหัสข้อผิดพลาดที่ดีหรือเขียนstdoutและส่งคืนรหัสข้อผิดพลาดที่ไม่ดี ในความเป็นจริงลองfind /root- สมมติว่าคุณไม่ได้ทำงานเป็นรากที่คุณควรจะได้รับ 2 สายพิมพ์ออกมา - "/ ราก" ได้รับการพิมพ์stdoutและ "พบ: ราก / อนุญาตปฏิเสธ" stderrได้รับการพิมพ์ และค้นหาส่งคืนรหัสส่งคืนสินค้าที่ไม่ดี
godlygeek

ปัญหาของ op ชัดเจนว่าจะบอกได้อย่างไรว่า stdout หรือ stderr
it_is_a_literature

0

โดยปกติ STDERR จะมีชื่อโปรแกรมต่อท้ายข้อความด้วยเครื่องหมายโคลอน

ตัวอย่าง:

rpm -zq some_utils 
rpm: -zq: unknown option

Vs

rpm -ql some_utils 
package some_utils is not installed

-1

ในการจับภาพและทดสอบหาข้อผิดพลาด:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.