Hiển thị stdout và stderr trong hai luồng riêng biệt


12

Tôi đang tìm cách phân tách trực quan thiết bị xuất chuẩn và thiết bị xuất chuẩn, để chúng không xen kẽ và để có thể dễ dàng xác định chúng. Lý tưởng nhất là thiết bị xuất chuẩn và thiết bị xuất chuẩn sẽ có các khu vực riêng biệt trên màn hình mà chúng được hiển thị, ví dụ như trong các cột khác nhau. Ví dụ: đầu ra trông như thế này:

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

thay vào đó sẽ trông giống như thế này:

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


Câu hỏi đó dường như không hỏi điều tương tự, và không có câu trả lời nào cung cấp những gì được hỏi ở đây.
Michael Homer

2
Sẽ hữu ích khi chuyển hướng các luồng đến hai tệp nhật ký khác nhau và sau đó sử dụng một cái gì đó như MultiTail trên chúng? vanheusden.com/multitail
Kusalananda

Tiện ích đầu ra chú thích có hữu ích không, hay bạn cần đầu ra trong các cột?
Jeff Schaller

Câu trả lời:


4

Bạn có thể sử dụng screentính năng phân chia dọc của 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"

Để sử dụng ví dụ như:

that-script 'ls / /not-here'

Ý tưởng là nó chạy màn hình với một tệp conf tạm thời bắt đầu hai cửa sổ màn hình theo bố cục chia dọc. Trong cái đầu tiên, chúng tôi chạy lệnh của bạn với stderr được kết nối với cái thứ hai.

Chúng tôi sử dụng một ống có tên cho cửa sổ thứ hai để giao tiếp thiết bị tty của nó với cửa sổ thứ nhất và cũng là ống thứ nhất để nói với ống thứ hai khi lệnh được thực hiện.

Ưu điểm khác so với các cách tiếp cận dựa trên đường ống là thiết bị xuất chuẩn và thiết bị xuất chuẩn vẫn được kết nối với các thiết bị tty, do đó nó không ảnh hưởng đến bộ đệm. Cả hai tấm cũng có thể được cuộn lên xuống một cách độc lập (sử dụng screenchế độ sao chép).

Nếu bạn chạy shell như bashtương tác với tập lệnh đó, bạn sẽ thấy dấu nhắc sẽ được hiển thị trên cửa sổ thứ hai, trong khi shell sẽ đọc nội dung bạn nhập trong cửa sổ đầu tiên khi các shell đó xuất ra dấu nhắc của chúng trên stderr.

Trong trường hợp bash, tiếng vang của những gì bạn gõ cũng sẽ xuất hiện trên cửa sổ thứ hai vì tiếng vang đó được xuất ra bởi vỏ (đường dẫn trong trường hợp bash) trên stderr. Với một số shell khác ksh93, nó sẽ hiển thị trên cửa sổ đầu tiên ( đầu ra echo của trình điều khiển thiết bị đầu cuối, không phải shell), trừ khi bạn đặt shell trong emacshoặc vichế độ với set -o emacshoặc set -o vi.


1

Đây là một giải pháp xấu xí dựa trên annotate-outputtập lệnh của Debian ANNOTATE-OUTPUT (1) . Không chắc chắn nếu đây là những gì bạn đang tìm kiếm nhưng có thể là một cái gì đó để bắt đầu:

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

Bạn có thể kiểm tra nó bằng cách sử dụng ./this_script another_scripthoặc command.


1

Tôi sẽ cố gắng phân tích phần sau của câu hỏi của bạn:

thay vào đó sẽ trông giống như thế này:

 ~ $ một số lệnh
 một số thông tin đầu ra hữu ích |
 đầu ra nhiều hơn | LRI: một lỗi
 tin nhắn khác | LRI: đã xảy ra
 ~ $ 

Nếu một người muốn phá vỡ những gì bạn muốn là:

1) stdoutLuồng sẽ không kết thúc mỗi dòng bằng một CR LFthay vào đó bằng '|' tính cách. Tất nhiên, điều này sẽ không liên kết hai luồng với nhau và việc căn chỉnh là không cần thiết bởi vì nó sẽ phải dự đoán độ dài của các dòng trong tương lai được thêm vào stdout, điều này tất nhiên là không thể.

2) Giả sử chúng ta quên đi việc căn chỉnh, sau đó chúng ta chỉ cần xuất dữ liệu stderrsau khi được xử lý bằng một đường ống có thêm "LRI:" vào đầu mỗi dòng. Tôi cho rằng điều này khá dễ dàng bằng cách tạo ra một kịch bản đơn giản và đảm bảo stderrluôn luôn xuất hiện thông qua kịch bản này.

Nhưng điều đó sẽ tạo ra một đầu ra như thế này:

~ $ một số lệnh
 một số thông tin đầu ra hữu ích |
 đầu ra nhiều hơn | LRI: một lỗi
 tin nhắn khác | LRI: đã xảy ra

Điều này không thực sự hữu ích, phải không? Ngoài ra tôi không tin, đó cũng là những gì bạn đang có sau đó!

Vấn đề với câu hỏi ban đầu, tôi nghĩ là bạn không tính đến tính chất nối tiếp của mỗi dòng được nối trong một luồng, liên quan đến thực tế là cả hai luồng có thể được viết không đồng bộ.

Tôi tin rằng giải pháp gần nhất có thể sẽ là sử dụng ncurses.
Xem.
[ http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[ http://invisible-island.net/ncurses/ncurses-intro.html#updating]

Để thực hiện những gì bạn đang có sau khi bạn cần đệm cả hai luồng và kết hợp chúng để tạo ra bộ đệm thứ ba lấy các phần tử từ cả hai bộ đệm. Sau đó đổ bộ đệm thứ ba vào màn hình đầu cuối bằng cách xóa màn hình đầu cuối và sơn lại mỗi lần bộ đệm thứ ba thay đổi. Nhưng đây là cách ncurseslàm việc, vậy tại sao lại phát minh lại bánh xe và không đưa nó lên từ đó?
Trong mọi trường hợp, bạn sẽ phải đảm nhận cách mà màn hình thiết bị đầu cuối được vẽ hoàn toàn ! Và căn chỉnh lại văn bản trong phiên bản in lại của màn hình theo ý muốn. Giống như một trò chơi video với các nhân vật đầu cuối.
Tôi hy vọng câu trả lời của tôi sẽ hữu ích trong việc làm rõ những hạn chế của những gì bạn đang có sau ...
Xin lỗi vì đã lặp lại điều này nhưng vấn đề lớn nhất với những gì bạn đã trình bày là "bộ xử lý" của luồng stdoutstderrluồng sẽ biết trước độ dài của các dòng trong tương lai được thêm vào như thế nào để căn chỉnh chúng đúng cách.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.