스크립트에 디버깅 옵션을 추가하려고 합니다. 보통 경고 등의 출력을 숨기고 싶어서 >/dev/null 2>&1
명령을 많이 넣습니다.
이제 스크립트를 디버그하려면 이러한 스크립트를 수동으로 제거하거나 각 명령을 if ... fi
test 변수 에 넣어야 합니다 $DEBUG
.
>/dev/null 2>&1
변수( $REDIR
)를 넣고 글을 쓰는 것이 command arg1 $REDIR
효과가 있을 것 같습니다 . 디버깅하고 싶다면 그냥 비워두세요 $REDIR
.
하지만 내 쉘에서 간단한 테스트를 해본 결과, 그런 식으로 작동하지 않는 것으로 나타났습니다.
~$ echo "bla" >/dev/null 2>&1
~$ REDIR=>/dev/null 2>&1
~$ echo "bla" $REDIR
bla
~$
명백한 이유로 "
or '
주변을 사용하는 것은 >/dev/null 2>&1
작동하지 않습니다.
그렇다면 왜 내 아이디어가 여기서 작동하지 않습니까? 명령어 등을 변수에 넣고 호출하는 것을 제가 잘못 이해한 걸까요?
답변1
리디렉션은 명령이 아니므로 이 방법으로 실행할 수 없습니다. 을 사용하면 완료할 수 있지만 eval
문제가 발생합니다.
원하는 작업을 수행하는 더 좋은 방법은 디버그 출력을 위한 함수를 갖는 것입니다.
function debugprint {
if [ ! -z "$debug" ]; then
echo "$1"
fi
}
debugprint "$(echo 'bla' 2>&1)"
이는 표준 오류를 표준 출력으로 리디렉션한 다음 debugprint
출력을 인수로 사용하여 호출됩니다. 이제 디버깅을 원할 때 해야 할 일은 $debug
null이 아닌 것으로 설정하는 것뿐입니다.
물론, 이것은 (인용과 관련된) 웜의 (다른) 캔을 열 수도 있습니다. 그냥 사용하고 싶을 수도 있는데 set -x
, 이는 디버깅 요구 사항에 충분할 수도 있고 충분하지 않을 수도 있습니다.
답변2
이를 위해 나는 보통 다음과 같은 함수를 정의합니다 run
. 대부분의 경우 이는 공백이 있는 매개변수와 기타 매개변수를 올바르게 처리합니다.
#!/bin/bash
run() {
if $DEBUG; then
v=$(exec 2>&1 && set -x && set -- "$@")
echo "#${v#*--}"
"$@"
else
"$@" >/dev/null 2>&1
fi
}
DEBUG=false
run echo "bla"
DEBUG=true
run echo "bla"
run printf "%s . %s . %s\n" bla "more bla" bla
산출:
$ bash debug.sh
# echo bla
bla
# printf '%s . %s . %s\n' bla 'more bla' bla
bla . more bla . bla
답변3
귀하의 경우 echo는 $REDIR
문자열 매개변수로 처리됩니다. 당신은 다음과 같은 것을 원합니다 :
~$ echo "bla" >/dev/null 2>&1
~$ REDIR='>/dev/null 2>&1'
~$ eval "echo bla $REDIR"
~$
그러나 빠르고 더러운 해킹을 시도하지 않는 한 Wouter Verhelst가 더 나은 솔루션을 제공합니다(실제로 그렇게 길거나 복잡하지 않습니다).
답변4
나는 내가 작성하는 모든 쉘 함수에 대해 동일한 작업을 수행합니다.
fn(){
echo some normal stderr debug stuff >&2 #if $DBG 2>stderr
dd if="\$DBG/please/report/on/this/file" #ditto
echo I DEFINITELY need to handle this >&3 #always stderr
( PATH=; ".some" oops I expect to handle ) 2>&4 #always /dev/null
echo and the regular stuff #always unaffected
} 4<>/dev/null 3>&2 2>&"$((${#DBG}?3:4))"
나는 몇 가지 이유로 이것을 좋아합니다.
len을 사용한
${#DBG}
평가는 항상 보장됩니다.>=0테스트의 정수 값 -$DBG
실제로 포함된 모든 값입니다.DBG=IFS=0
예를 들어, 이는 수학을 안전하게 만듭니다.함수가 실행될 때마다 실제 작업은 한 번만 수행됩니다
open()
. 그/dev/null
외에는 ./dev/null
#fd>&4
디버그 출력(활성화할 수 있음
set -x
)은 기본적으로 대화형 셸에 함수를 덤프합니다.~하지 않는 한환경 변수를$DBG
null이 아닌 값으로 명시적으로 설정했습니다.- 비어 있지 않은 경우
$DBG
리디렉션된 수학적 확장은 자체를 가리키며 이는 로 평가됩니다2>&3
. - 그러나 그 외에는 공개 설명자로 평가되므로
2>&4
공개/dev/null
설명자로 이동합니다. - 일반적으로 식별하고 저장한 함수의 20줄 실행 추적을 볼 필요는 없지만
~/.sh/fn/...
, 식별했다면 관련된 명령줄은 완전히 다른 것일 수 있습니다set -x
. $DBG
null/not set인 경우에도 편리하지만set -x
예$PS4
stderr로 이동하지 않지만#fd>&3
여전히 도달할 수 있는 명령별 평가 종료를 열기 때문에 활성화됩니다 .
- 비어 있지 않은 경우
합리적인 방식으로 상속을 구현합니다.
- 다른 함수를 호출하는 함수는
$DBG
어떤 방식으로든 이 값에 영향을 미칠 수 없습니다. 따라서 이미 쓸 수 없는 경우 기본적으로 stderr에 쓰기를 시작할 수 있습니다. - 설정되지 않거나 null 인 경우
$DBG
호출하는 모든 하위 함수는#fd3
호출하지 않는 한 Even의 의미를 잃습니다child_fn 2>&3
. 이 경우 상위 함수가 명시적으로 stderr에 쓰는 것과 동일한 기회를 얻습니다. - 그것할 수 있는설정하더라도
$DBG
이러한 하위 기능을 조용하게 설정하지 않습니다.$DBG
- 그리고 그것은 할 수 있다놓다
$DBG
이를 통해 최상위 함수를 호출할 수 있습니다.뒤쪽에기본 stderr 출력이 활성화됩니다.
- 다른 함수를 호출하는 함수는
나는 stderr의 복사본을 보관하므로
#fd>&3
함수가 필요한 경우 해당 설명자에서 stderr에 명시적으로 쓸 수 있습니다.(위의 경우는 제외).설명자는 함수를 래핑하는 복합 명령에만 연결되어 있기 때문에 fds 2, 3, 4의 현재 쉘 값에 영향을 주지 않고 스스로 닫힙니다.
- 청소
{3,4}>&-
는 필요하지 않습니다.
- 청소