Tampilkan stdout dan stderr dalam dua aliran terpisah


12

Saya mencari cara untuk memisahkan stdout dan stderr secara visual, sehingga mereka tidak saling berhubungan dan agar mereka dapat dengan mudah diidentifikasi. Idealnya, stdout dan stderr akan memiliki area terpisah pada layar di mana mereka ditampilkan, misalnya dalam kolom yang berbeda. Sebagai contoh, output yang akan terlihat seperti ini:

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

sebaliknya akan terlihat seperti ini:

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


Pertanyaan itu sepertinya tidak menanyakan hal yang sama, dan tidak ada jawaban yang memberikan apa yang ditanyakan di sini.
Michael Homer

2
Apakah bermanfaat untuk mengarahkan aliran ke dua file log yang berbeda dan kemudian menggunakan sesuatu seperti MultiTail? vanheusden.com/multitail
Kusalananda

Apakah utilitas annotate-output terlihat berguna, atau apakah Anda memerlukan output dalam kolom?
Jeff Schaller

Jawaban:


4

Anda dapat menggunakan screenfitur pemisahan vertikal 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"

Untuk digunakan misalnya sebagai:

that-script 'ls / /not-here'

Idenya adalah bahwa ia menjalankan layar dengan file conf sementara yang memulai dua jendela layar dalam tata letak split vertikal. Di yang pertama, kami menjalankan perintah Anda dengan stderr terhubung ke yang kedua.

Kami menggunakan pipa bernama untuk jendela kedua untuk mengkomunikasikan perangkat tty-nya ke yang pertama, dan juga untuk yang pertama memberi tahu yang kedua ketika perintah dilakukan.

Keuntungan lain dibandingkan dengan pendekatan berbasis pipa adalah stdout dan stderr perintah masih terhubung ke perangkat tty, sehingga tidak mempengaruhi buffering. Kedua panel juga dapat digulir ke atas dan ke bawah secara independen (menggunakan screenmode salin).

Jika Anda menjalankan shell seperti bashberinteraksi dengan skrip itu, Anda akan melihat prompt akan ditampilkan di jendela kedua, sementara shell akan membaca apa yang Anda ketikkan di jendela pertama saat shell-shell tersebut mengeluarkan prompt mereka di stderr.

Dalam hal ini bash, gema dari apa yang Anda ketik juga akan muncul di jendela kedua karena gema itu dihasilkan oleh shell (readline dalam kasus bash) pada stderr juga. Dengan beberapa shell lain seperti ksh93, itu akan ditampilkan di jendela pertama ( gema output oleh driver perangkat terminal, bukan shell), kecuali jika Anda meletakkan shell dalam emacsatau vimode dengan set -o emacsatau set -o vi.


1

Ini adalah solusi jelek berdasarkan annotate-outputscript Debian ANNOTATE-OUTPUT (1) . Tidak yakin apakah ini yang Anda cari tetapi bisa menjadi sesuatu untuk memulai:

#!/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

Anda dapat mengujinya menggunakan ./this_script another_scriptatau command.


1

Saya akan mencoba menganalisis bagian pertanyaan Anda berikut ini:

sebaliknya akan terlihat seperti ini:

 ~ $ beberapa perintah
 beberapa info keluaran bermanfaat |
 lebih banyak output | GALAT: kesalahan
 pesan lain | GALAT: telah terjadi
 ~ $ 

Jika seseorang ingin menguraikan apa yang Anda inginkan adalah:

1) stdoutAliran tidak akan mengakhiri setiap baris dengan CR LFmelainkan dengan '|' karakter. Ini tidak akan menyatukan dua aliran bersama tentu saja, dan penyelarasan keluar dari pertanyaan karena harus memprediksi panjang garis masa depan ditambahkan ke stdout, yang tentu saja tidak mungkin.

2) Dengan asumsi kita lupa tentang penyelarasan maka kita hanya akan output stderrsetelah diproses oleh pipa yang menambahkan "GALAT:" ke awal setiap baris. Saya kira ini cukup mudah dengan membuat skrip sederhana dan memastikan stderrselalu keluar melalui skrip ini.

Tapi itu akan menghasilkan output seperti ini:

~ $ beberapa perintah
 beberapa info keluaran bermanfaat |
 lebih banyak output | GALAT: kesalahan
 pesan lain | GALAT: telah terjadi

Yang mana tidak terlalu membantu, bukan? Saya juga tidak percaya, itu yang Anda cari juga!

Masalah dengan pertanyaan awal, saya pikir adalah bahwa Anda tidak memperhitungkan sifat serial dari setiap baris ditambahkan dalam aliran, sehubungan dengan fakta bahwa kedua aliran dapat ditulis secara tidak sinkron.

Saya percaya bahwa solusi terdekat yang mungkin akan digunakan ncurses.
Lihat.
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Untuk melakukan apa yang Anda lakukan setelah Anda perlu buffer kedua aliran dan menggabungkannya untuk menghasilkan buffer ketiga yang mengambil elemen dari kedua buffer. Kemudian buang buffer ketiga ke layar terminal dengan menghapus layar terminal dan mengecat ulang setiap kali buffer ketiga berubah. Tapi ini cara ncurseskerjanya, jadi mengapa menemukan kembali roda dan tidak mengambilnya dari sana?
Bagaimanapun, Anda harus mengambil alih cara layar terminal dicat seluruhnya ! Dan luruskan kembali teks dalam versi layar yang dicetak ulang sesuka Anda. Mirip seperti gim video dengan karakter terminal.
Saya harap jawaban saya akan membantu dalam menjelaskan batasan apa yang Anda cari ...
Maafkan saya untuk mengulangi ini tetapi masalah terbesar dengan apa yang Anda tunjukkan adalah bagaimana "prosesor" dari stdoutdan stderraliran tahu sebelumnya panjang garis masa depan ditambahkan ke dalamnya untuk menyelaraskan mereka dengan benar.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.