스크립트
#!/usr/bin/env bash
# Exit on error. Append "|| true" if you expect an error.
set -o errexit
# Exit on error inside any functions or subshells.
set -o errtrace
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
set -o nounset
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
set -o pipefail
# Turn on traces, useful while debugging but commented out by default
set -o xtrace
bash_backtrace() {
echo TEST
ls -l /proc/$$/fd >&2
}
trap bash_backtrace ERR
CMD="ls /does-not-exist"
eval "${CMD}" > /tmp/foo
exit
산출
$ ./test.sh
+ trap bash_backtrace ERR
+ CMD='ls /does-not-exist'
+ eval 'ls /does-not-exist'
++ ls /does-not-exist
ls: cannot access /does-not-exist: No such file or directory
+++ bash_backtrace
+++ echo TEST
+++ ls -l /proc/19650/fd
total 0
lrwx------. 1 sbarre sbarre 64 Apr 18 15:57 0 -> /dev/pts/0
l-wx------. 1 sbarre sbarre 64 Apr 18 15:57 1 -> /tmp/foo
lrwx------. 1 sbarre sbarre 64 Apr 18 15:57 10 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 18 15:57 2 -> /dev/pts/0
lr-x------. 1 sbarre sbarre 64 Apr 18 15:57 255 -> /home/sbarre/test.sh
내 평가에서 오류가 발생하고 트랩에 걸리기 때문에 stdout은 여전히 /tmp/foo를 가리킵니다. 따라서 내 트랩 기능의 모든 에코는 터미널이 아닌 해당 파일로 이동합니다.
트랩 기능에서 어떻게 안전하게 재설정할 수 있나요? 표준 출력을 리디렉션하는 방식으로 스크립트 자체가 실행되는 상황을 처리해야 합니다.
$ ./test.sh > log.txt
나는 stdout을 "수정"하고 싶습니다 log.txt
./tmp/foo
답변1
이것이 바로 표준 오류 스트림의 목적입니다.
bash_backtrace() {
echo TEST >&2
ls -l "/proc/$$/fd" >&2
}
트랩이 진단 메시지( TEST
)를 출력하고 있습니다. 이는 표준 출력이 아니라 표준 오류로 이동해야 합니다.
답변2
복제 핸들을 사용한 다음 트랩 기능에서 복원하여 exec
이 문제를 해결했습니다 . 이렇게 하면 스크립트가 시작될 때 STDERR이 가는 곳마다 트랩의 출력도 그곳으로 이동합니다.
스크립트
#!/usr/bin/env bash
# Exit on error. Append "|| true" if you expect an error.
set -o errexit
# Exit on error inside any functions or subshells.
set -o errtrace
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
set -o nounset
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
set -o pipefail
# Turn on traces, useful while debugging but commented out by default
set -o xtrace
# Copy STDOUT and STDERR
exec 3>&1 4>&2
bash_backtrace() {
ls -l /proc/$$/fd >$(tty)
# Restore STDOUT and STDERR
exec 1>&3 2>&4
echo TEST
echo >&2 ERROR
ls -l /proc/$$/fd >&2
}
trap bash_backtrace ERR
CMD="ls /does-not-exist"
eval "${CMD}" > /tmp/foo 2> /tmp/bla
exit
산출
+ exec
+ trap bash_backtrace ERR
+ CMD='ls /does-not-exist'
+ eval 'ls /does-not-exist'
total 0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 0 -> /dev/pts/0
l-wx------. 1 sbarre sbarre 64 Apr 19 13:22 1 -> /tmp/foo
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 10 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 11 -> /dev/pts/0
l-wx------. 1 sbarre sbarre 64 Apr 19 13:22 2 -> /tmp/bla
lr-x------. 1 sbarre sbarre 64 Apr 19 13:22 255 -> /home/sbarre/test.sh
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 3 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 4 -> /dev/pts/0
+++ echo TEST
TEST
+++ echo ERROR
ERROR
+++ ls -l /proc/11910/fd
total 0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 0 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 1 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 10 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 11 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 2 -> /dev/pts/0
lr-x------. 1 sbarre sbarre 64 Apr 19 13:22 255 -> /home/sbarre/test.sh
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 3 -> /dev/pts/0
lrwx------. 1 sbarre sbarre 64 Apr 19 13:22 4 -> /dev/pts/0