두 개의 별도 스트림에 stdout 및 stderr 표시

두 개의 별도 스트림에 stdout 및 stderr 표시

저는 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
~$                       |

답변1

screenGNU 의 수직 분할 기능을 사용할 수 있습니다 :

#! /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,에코입력한 내용이 두 번째 창에도 나타납니다.에코bash또한 쉘에 의해 stderr로 출력됩니다(이 경우 readline). 예를 들어 다른 쉘의 경우 ksh93첫 번째 창에 표시됩니다(에코emacs셸을 사용하거나 셸을 또는 vi모드 로 설정하지 않는 한 셸이 아닌 터미널 장치 드라이버에 의해 출력됩니다 .set -o emacsset -o vi

답변2

annotate-output데비안 스크립트를 기반으로 한 추악한 솔루션은 다음과 같습니다.코멘트 출력(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_script를 사용 하거나 테스트 할 수 있습니다 command.

답변3

귀하의 질문에서 다음 부분을 분석해 보겠습니다.

대신 다음과 같습니다.

~$ 일부 명령
 유용한 출력 정보 |
 추가 출력|오류: 오류
 다른 메시지 | 오류가 발생했습니다.
 ~$

누구든지 원하는 것을 분석하려면 다음을 수행하십시오.

1) stdout스트림은 각 줄을 "|"로 끝내지 않고 CR LF대신 "|" 문자로 끝냅니다. 물론 이는 두 스트림을 함께 정렬하지 않으며 에 추가할 향후 행의 길이를 예측해야 하기 때문에 정렬이 불가능합니다 stdout. 물론 이는 불가능합니다. 2) 정렬을 잊어버렸다고 가정하고 각 줄의 시작 부분에 "ERROR:"를 추가하는 파이프로 처리한 후 결과를

간단히 출력하겠습니다 . stderr간단한 스크립트를 만들고 stderr항상 이를 수행하면 이 작업을 수행하는 것이 매우 쉽다고 생각합니다.

그러나 이렇게 하면 다음과 같은 출력이 생성됩니다.

~$ 일부 명령
 유용한 출력 정보|
 추가 출력|오류: 오류
 다른 메시지 | 오류가 발생했습니다.

그건 별로 도움이 되지 않죠, 그렇죠? 나도 믿지 않는다. 당신도 추구하는 것이 이것이다!

원래 질문의 문제점은 두 스트림이 비동기식으로 작성될 수 있기 때문에 스트림에 추가된 각 행의 직렬 특성을 고려하지 않는다는 것입니다.

가장 가까운 해결책은 ncurses.see 를 사용하는 것입니다
.
[http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[http://invisible-island.net/ncurses/ncurses-intro.html#updating]

수행하려는 작업을 수행하려면 두 개의 스트림을 버퍼링하고 이를 결합하여 두 버퍼에서 요소를 가져오는 세 번째 버퍼를 생성해야 합니다. 그런 다음 터미널 화면을 지우고 세 번째 버퍼가 변경될 때마다 다시 그려서 세 번째 버퍼를 터미널 화면에 덤프합니다. 하지만 이것이 효과가 있는 것인데 ncurses왜 거기에서 시작하는 대신 바퀴를 재발명해야 할까요?
무슨 일이 있어도 꼭 해야 할 일터미널 화면이 그려지는 방식을 완전히 장악! 필요에 따라 화면 재인쇄 버전의 텍스트를 다시 정렬합니다. 터미널 캐릭터가 있는 비디오 게임과 매우 유사합니다.
내 대답이 당신이 추구하는 한계를 명확히하는 데 도움이되기를 바랍니다 ... 반복해서 죄송합니다. 그러나 당신이 보여준 것의 가장 큰 문제는
스트림의 "프로세서"가 다음 줄의 길이를 미리 아는 방법 입니다. 올바르게 정렬하려면 추가하세요.stdoutstderr

관련 정보