bash :`-x` echoing에서 개별 행을 이스케이프 처리


11

bash에서 -x옵션으로 실행할 때 개별 명령을 에코하지 않을 수 있습니까?

가능한 한 깔끔하게 출력하려고 노력하고 있으므로 스크립트의 특정 부분을 하위 쉘에서 실행하고 set +x있습니다. 그러나 행 set +x자체는 여전히 에코되며 출력에 중요한 정보를 추가하지 않습니다.

나는 과거로 나쁜 기억을 가지고 있습니다.로 .bat실행 echo on하면 개별 라인은로 시작하여 면제 될 수 있습니다 @. bash에 동등한 것이 있습니까?

#!/bin/bash -x

function i_know_what_this_does() {
  (
    set +x
    echo do stuff
  )
}

echo the next-next line still echoes 'set +x', is that avoidable?
i_know_what_this_does
echo and we are back and echoing is back on

위를 실행하면 출력은 다음과 같습니다.

+ echo the next-next line still echoes 'set +x,' is that 'avoidable?'
the next-next line still echoes set +x, is that avoidable?
+ i_know_what_this_does
+ set +x
do stuff
+ echo and we are back and echoing is back on
and we are back and echoing is back on

답변:


22

xtrace리디렉션 할 수 있도록 출력은 표준 에러로 이동 stderr/dev/null:

i_know_what_this_does() {
  echo do stuff
} 2> /dev/null

함수 내에서 실행되는 명령의 오류를 계속 확인하려면 할 수 있습니다

i_know_what_this_does() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

서브 쉘을 통해 해당 기능에 대한 로컬 범위를 제공하는 (...)대신 사용하십시오 {...}. bash, 버전 4.4는 이제 local -Almquist 쉘에서와 같이 지원 하여 옵션을 함수에 로컬로 만들 수 있으므로 ( set -o localoptionsin 과 유사 zsh) 다음을 수행하여 서브 쉘을 피할 수 있습니다.

i_know_what_this_does() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

bash4.0에서 4.3에 대한 대안 은 $BASH_XTRACEFD변수 를 사용 하고이를 위해 전용 파일 디스크립터를 여는 것 /dev/null입니다.

exec 9> /dev/null
set -x
i_know_what_this_does() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

close-on-exec 플래그 bash로 fd를 표시하는 기능이 없기 때문에 , fd를 다른 명령으로 유출하는 부작용이 있습니다.

이 참조 locvar.sh 구현하기 위해 몇 가지 기능이 포함되어 현지 로 제공 또한 POSIX 스크립트의 변수 및 함수에 대한 범위와 trace_fnuntrace_fn기능들을 만들기 위해 xtrace의 D를 여부를.


단! 함수 자체에 적용 할 수있는 수정자가 있는지 확인하려고했지만 단순히 stderr을 리디렉션하는 것에 대해서는 생각하지 않았습니다. 감사!
clacke

1
Btw, 같은 페이지의 stchaz.free.fr/which_interpreter 는 매우 훌륭하고 혼란 스럽습니다. :-)
clacke

이제 두 번째 방법으로 다시 돌아 왔습니다. 유용한 stderr 출력을 침묵시키지 않고 set + x를 침묵시킵니다. 다시 감사합니다!
clacke

2

set +x인쇄 되는 이유 set -x는 "실행 하기 전에 확장 명령을 사용하여 실행할 명령을 인쇄합니다."라는 메시지를 표시 하기 때문 입니다. 내가 아는 한, 그 일이 일어나지 않도록 막을 방법은 없습니다.


0

찾고있는 솔루션은 다음과 같습니다.

function xtrace() {
  # Print the line as if xtrace was turned on, using perl to filter out
  # the extra colon character and the following "set +x" line.
  (
    set -x
    # Colon is a no-op in bash, so nothing will execute.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

원래 명령은 ID 변환에서 동일한 쉘에서 실행됩니다. 실행 직전에 인수의 비재 귀적 xtrace를 얻습니다. 이를 통해 모든 "echo"명령의 복제본이있는 스팸 stederr없이 관심있는 명령을 xtrace 할 수 있습니다.

# Example
echo "About to do something complicated ..."
xtrace do_something_complicated

또는 피하기 위해 perl(및 여러 줄 명령의 문제) :+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
Stéphane Chazelas

죄송합니다, unix.stackexchange.com/a/60049/17980 이 내가 찾고 있던 해결책입니다. :-) set -x기동은 저와 비교해서 아무것도 사지 printf >&2 '+ %s\n' "$*"않습니까?
clacke

에서와 같이 :xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
clacke
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.