แสดง stdout และ stderr ในสองสตรีมที่แยกกัน


13

ฉันกำลังมองหาวิธีที่จะแยก stdout และ stderr ทางสายตาเพื่อที่พวกเขาจะไม่สอดแทรกและเพื่อให้สามารถระบุได้ง่าย ตามหลักการแล้ว stdout และ stderr จะมีพื้นที่แยกต่างหากบนหน้าจอที่แสดงเช่นในคอลัมน์ต่างๆ ตัวอย่างเช่นผลลัพธ์ที่จะมีลักษณะเช่นนี้:

~$ some command
some useful output info
ERROR: an error
more output
ERROR: has occurred
another message
~$ 

จะมีลักษณะเช่นนี้แทน:

~$ some command          |
some useful output info  |
more output              |  ERROR: an error
another message          |  ERROR: has occurred
~$                       |


คำถามนั้นดูเหมือนจะไม่ถามในสิ่งเดียวกันและไม่มีคำตอบใดที่ให้ที่นี่
Michael Homer

2
การเปลี่ยนเส้นทางสตรีมไปยังไฟล์บันทึกที่แตกต่างกันสองไฟล์แล้วใช้ประโยชน์จาก MultiTail กับไฟล์เหล่านั้นหรือไม่ vanheusden.com/multitail
Kusalananda

ยูทิลิตีหมายเหตุประกอบเอาท์พุทดูมีประโยชน์หรือไม่หรือคุณต้องการผลลัพธ์เป็นคอลัมน์?
Jeff Schaller

คำตอบ:


5

คุณสามารถใช้screenคุณสมบัติแบ่งแนวตั้งของGNU :

#! /bin/bash -
tmpdir=$(mktemp -d) || exit
trap 'rm -rf "$tmpdir"' EXIT INT TERM HUP

FIFO=$tmpdir/FIFO
mkfifo "$FIFO" || exit

conf=$tmpdir/conf

cat > "$conf" << 'EOF' || exit
split -v
focus
screen -t stderr sh -c 'tty > "$FIFO"; read done < "$FIFO"'
focus
screen -t stdout sh -c 'read tty < "$FIFO"; eval "$CMD" 2> "$tty"; echo "[Command exited with status $?, press enter to exit]"; read prompt; echo done > "$FIFO"'
EOF

CMD="$*"
export FIFO CMD

screen -mc "$conf"

เพื่อใช้เป็นตัวอย่างเช่น:

that-script 'ls / /not-here'

แนวคิดก็คือมันรันหน้าจอด้วยไฟล์ conf ชั่วคราวที่เริ่มต้นหน้าต่างหน้าจอสองหน้าต่างในเค้าโครงแบบแยกแนวตั้ง ในอันแรกเราเรียกใช้คำสั่งของคุณโดย stderr เชื่อมต่อกับอันที่สอง

เราใช้ไพพ์ที่มีชื่อสำหรับหน้าต่างที่สองเพื่อสื่อสารอุปกรณ์ tty ของมันกับหน้าต่างแรกและสำหรับคนแรกที่จะบอกหนึ่งในหน้าต่างที่สองเมื่อคำสั่งเสร็จสิ้น

ข้อได้เปรียบอื่น ๆ เมื่อเปรียบเทียบกับวิธีการอิงตามไปป์คือ stdout และ stderr ของคำสั่งยังคงเชื่อมต่อกับอุปกรณ์ tty ดังนั้นจึงไม่มีผลต่อการบัฟเฟอร์ บานหน้าต่างทั้งสองยังสามารถเลื่อนขึ้นและลงได้อย่างอิสระ (โดยใช้screenโหมดการคัดลอก)

หากคุณเรียกใช้เชลล์เช่นbashโต้ตอบกับสคริปต์นั้นคุณจะสังเกตเห็นพรอมต์จะปรากฏขึ้นในหน้าต่างที่สองในขณะที่เชลล์จะอ่านสิ่งที่คุณพิมพ์ในหน้าต่างแรกเมื่อเชลล์เหล่านั้นส่งเอาต์พุตพร้อมต์บน stderr

ในกรณีของbashการสะท้อนของสิ่งที่คุณพิมพ์จะปรากฏบนหน้าต่างที่สองเป็นที่ก้องจะออกจากเปลือก (ReadLine ในกรณีของbash) บน stderr เช่นกัน กับบางส่วนเปลือกหอยอื่น ๆ เช่นksh93มันจะแสดงบนหน้าต่างแรก ( ก้องเอาท์พุทโดยไดรเวอร์อุปกรณ์ปลายทางไม่เชลล์) เว้นแต่คุณใส่เปลือกในemacsหรือviโหมดที่มีหรือset -o emacsset -o vi


1

นี้เป็นทางออกที่น่าเกลียดอยู่บนพื้นฐานของannotate-outputสคริปต์ของ Debian คำอธิบายเอาท์พุท (1) ไม่แน่ใจว่านี่คือสิ่งที่คุณกำลังมองหา แต่อาจเป็นสิ่งที่เริ่มต้นด้วย:

#!/bin/bash 

readonly col=150 # column to start error output 

add_out ()
{
    while IFS= read -r line; do
        echo "$1: $line"
    done
    if [ ! -z "$line" ]; then
        echo -n "$1: $line"
    fi
}

add_err ()
{
    while IFS= read -r line; do
        printf "%*s  %s %s: %s\n" $col "|" "$1" "$line"
    done
    if [ ! -z "$line" ]; then
        printf "%*s %s: %s" $col "$1" "$line"
    fi
}

cleanup() { __st=$?; rm -rf "$tmp"; exit $__st; }
trap cleanup 0
trap 'exit $?' 1 2 13 15

tmp=$(mktemp -d --tmpdir annotate.XXXXXX) || exit 1
OUT=$tmp/out
ERR=$tmp/err

mkfifo $OUT $ERR || exit 1

add_out OUTPUT < $OUT &
add_err ERROR < $ERR &

echo "I: Started $@"
"$@" > $OUT 2> $ERR ; EXIT=$?
rm -f $OUT $ERR
wait

echo "I: Finished with exitcode $EXIT"

exit $EXIT

คุณสามารถทดสอบได้โดยใช้หรือ./this_script another_scriptcommand


1

ฉันจะพยายามวิเคราะห์ส่วนต่อไปนี้ของคำถามของคุณ:

จะมีลักษณะเช่นนี้แทน:

 ~ $ คำสั่งบางอย่าง
 ข้อมูลผลลัพธ์ที่เป็นประโยชน์บางอย่าง |
 ผลผลิตมากขึ้น ข้อผิดพลาด: ข้อผิดพลาด
 ข้อความอื่น | ข้อผิดพลาด: เกิดขึ้น
 ~ $ 

หากมีใครต้องการที่จะทำลายสิ่งที่คุณต้องการคือ

1) stdoutกระแสจะไม่จบแต่ละบรรทัดด้วยCR LFแต่แทนที่ด้วย '|' ตัวละคร สิ่งนี้จะไม่จัดแนวลำธารทั้งสองเข้าด้วยกันแน่นอนและการจัดวางไม่เป็นไปตามคำถามเพราะจะต้องทำนายความยาวของบรรทัดในอนาคตที่เพิ่มเข้ามาstdoutซึ่งเป็นไปไม่ได้แน่นอน

2) สมมติว่าเราลืมการจัดตำแหน่งจากนั้นเราก็จะแสดงผลลัพธ์stderrหลังจากที่ถูกประมวลผลโดยไพพ์ไลน์ที่เพิ่ม "ข้อผิดพลาด:" ไปยังจุดเริ่มต้นของแต่ละบรรทัด ฉันคิดว่ามันค่อนข้างง่ายโดยการสร้างสคริปต์ง่าย ๆ และตรวจสอบให้แน่ใจว่าstderrสคริปต์นี้ออกมาเสมอ

แต่นั่นจะสร้างผลลัพธ์เช่นนี้

~ $ คำสั่งบางอย่าง
 ข้อมูลผลลัพธ์ที่เป็นประโยชน์บางอย่าง |
 ผลผลิตมากขึ้น ข้อผิดพลาด: ข้อผิดพลาด
 ข้อความอื่น | ข้อผิดพลาด: เกิดขึ้น

อันไหนไม่เป็นประโยชน์จริงๆเหรอ? นอกจากนี้ฉันไม่เชื่อว่ามันเป็นสิ่งที่คุณหลังจากนั้นด้วย!

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

ดู. [ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/] [ http://invisible-island.net/ncurses/ncurses-intro.html#updating]ncurses




ในการทำสิ่งที่คุณเป็นหลังจากที่คุณต้องการบัฟเฟอร์ทั้งสองสตรีมและรวมเข้าด้วยกันเพื่อสร้างบัฟเฟอร์ที่สามที่ใช้องค์ประกอบจากบัฟเฟอร์ทั้งสอง จากนั้นดัมพ์บัฟเฟอร์ที่สามลงในหน้าจอเทอร์มินัลโดยการลบหน้าจอเทอร์มินัลและทาสีใหม่ทุกครั้งที่การเปลี่ยนบัฟเฟอร์ที่สาม แต่นี่เป็นวิธีการncursesทำงานดังนั้นทำไมต้องคิดค้นล้อใหม่และไม่นำขึ้นจากที่นั่น
ไม่ว่าในกรณีใดคุณจะต้องควบคุมวิธีการทาสีหน้าจอเทอร์มินัลทั้งหมด ! และปรับแนวข้อความในเวอร์ชันที่พิมพ์ซ้ำของหน้าจอตามที่คุณต้องการ เหมือนวิดีโอเกมที่มีตัวละครเทอร์มินัล
ฉันหวังว่าคำตอบของฉันจะเป็นประโยชน์ในการชี้แจงข้อ จำกัด ของสิ่งที่คุณเป็นหลังจาก ...
ขอโทษด้วยสำหรับการทำซ้ำ แต่ปัญหาที่ใหญ่ที่สุดของสิ่งที่คุณแสดงคือ "ตัวประมวลผล" ของลำธารstdoutและstderrรู้ล่วงหน้าเกี่ยวกับความยาวของบรรทัดในอนาคตที่เพิ่มเข้ามาเพื่อปรับแนวให้เหมาะสม

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