저는 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
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
,에코입력한 내용이 두 번째 창에도 표시됩니다.에코stderr의 쉘( 의 경우 readline bash
)에서도 출력됩니다. 와 같은 다른 쉘을 사용하면 ksh93
첫 번째 창에 표시됩니다(에코또는 를 사용하여 셸을 emacs
또는 vi
모드로 설정하지 않는 한 셸이 아닌 터미널 장치 드라이버에 의해 출력됩니다 .set -o emacs
set -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) 스트림은 각 줄을 a로 끝나지 않고 대신 '|'로 stdout
끝냅니다. CR LF
성격. 물론 이것은 두 스트림을 함께 정렬하지 않으며 에 추가되는 향후 라인의 길이를 예측해야 하기 때문에 정렬은 의문의 여지가 없습니다. stdout
물론 이는 불가능합니다.
2) 정렬을 잊어버렸다고 가정하면 stderr
각 줄의 시작 부분에 "ERROR:"를 추가하는 파이프라인에 의해 처리된 후 간단히 출력됩니다. 간단한 스크립트를 만들어서 stderr
항상 이 스크립트를 통해 나오는지 확인하면 이것이 매우 쉽다고 생각합니다.
그러나 그러면 다음과 같은 출력이 생성됩니다.
~$ 일부 명령 유용한 출력 정보| 더 많은 출력| 오류: 오류 다른 메시지| 오류: 발생했습니다.
실제로 도움이 되지 않는 것은 무엇입니까? 또한 나는 믿지 않습니다. 그것은 당신도 추구하는 것입니다!
초기 질문의 문제는 두 스트림이 모두 비동기적으로 작성될 수 있다는 사실과 관련하여 스트림에 추가된 각 줄의 직렬 특성을 고려하지 않는다는 것입니다.
나는 가장 가까운 해결책이 ncurses
.
보다.
[http://www.tldp.org/HOWTO/html_single/NCURSES-Programming-HOWTO/]
[http://invisible-island.net/ncurses/ncurses-intro.html#updating]
현재 작업을 수행하려면 두 스트림을 모두 버퍼링하고 결합하여 두 버퍼에서 요소를 가져오는 세 번째 버퍼를 생성해야 합니다. 그런 다음 터미널 화면을 지우고 세 번째 버퍼가 변경될 때마다 다시 그려서 세 번째 버퍼를 터미널 화면에 덤프합니다. 하지만 이것이 작동하는 방식인데 ncurses
왜 바퀴를 재발명하고 거기서부터 시작하지 않습니까?
어쨌든 당신은해야 할 것입니다터미널 화면이 완전히 그려지는 방식을 이어받습니다.! 그리고 재인쇄된 화면의 텍스트를 원하는 대로 다시 정렬하세요. 터미널 캐릭터가 포함된 비디오 게임과 매우 흡사합니다.
내 대답이 당신이 추구하는 것의 한계를 명확히 하는 데 도움이 되기를 바랍니다...
이것을 반복해서 실례합니다. 그러나 당신이 보여준 것의 가장 큰 문제는 stdout
및 stderr
스트림의 "프로세서"가 스트림의 길이를 미리 알 수 있는 방법입니다. 적절하게 정렬하기 위해 향후 행이 추가됩니다.