`set -x`와 같은 쉘 옵션의 값을 복원하는 방법은 무엇입니까?


47

set -x스크립트 시작 부분에서 맹목적으로 설정하는 대신 "실행 취소"(설정하기 전에 상태로 돌아 가기)를 원합니다 +x. 이게 가능해?

추신 : 나는 이미 여기를 확인 했습니다 . 내가 알 수있는 한 내 질문에 대답하지 않은 것 같습니다.

답변:


58

요약

반대로하려면 a set -x를 실행하십시오 set +x. 대부분의 경우 문자열의 반대 set -str+: 와 같은 문자열입니다 set +str.

일반적으로 모든 bash errexit옵션 ( set명령으로 변경) 을 복원 하려면 다음을 수행하십시오 (bash shopt옵션 에 대해서는 아래를 참조하십시오 ).

oldstate="$(set +o); set -$-"                # POSIXly store all set options.
.
.
set -vx; eval "$oldstate"         # restore all options stored.

더 긴 설명

세게 때리다

이 명령은

shopt -po xtrace

옵션 상태를 반영하는 실행 가능 문자열을 생성합니다. p플래그 수단은 인쇄하고, o우리가에 의해 옵션 (들) 설정에 대한 요구되는 플래그 지정 set(에 의해 옵션 (들) 집합에 반대 명령 shopt명령). 이 문자열을 변수에 할당하고 스크립트 끝에서 변수를 실행하여 초기 상태를 복원 할 수 있습니다.

# store state of xtrace option.
tracestate="$(shopt -po xtrace)"

# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"

# restore the value of xtrace to its original value.
eval "$tracestate"

이 솔루션은 여러 옵션에 동시에 작동합니다.

oldstate="$(shopt -po xtrace noglob errexit)"

# change options as needed
set -x
set +x
set -f
set -e
set -x

# restore to recorded state:
set +vx; eval "$oldstate"

추가 set +vx하면 긴 옵션 목록이 인쇄되지 않습니다.


옵션 이름을 나열하지 않으면

oldstate="$(shopt -po)"

모든 옵션의 값을 제공합니다. 그리고 o깃발 을 남기지 않으면 shopt옵션을 사용 하여 동일한 작업을 수행 할 수 있습니다.

# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"

# store state of all options.
oldstate="$(shopt -p)"

set옵션이 설정되어 있는지 테스트해야하는 경우 가장 관용적 인 방법은 다음과 같습니다.

[[ -o xtrace ]]

다른 두 가지 유사한 테스트보다 낫습니다.

  1. [[ $- =~ x ]]
  2. [[ $- == *x* ]]

모든 테스트에서 다음과 같이 작동합니다.

# record the state of the xtrace option in ts (tracestate):
[ -o xtrace ] && ts='set -x' || ts='set +x'

# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"

# set the xtrace option back to what it was.
eval "$ts"

shopt옵션 상태를 테스트하는 방법은 다음과 같습니다 .

if shopt -q dotglob
then
        # dotglob is set, so “echo .* *” would list the dot files twice.
        echo *
else
        # dotglob is not set.  Warning: the below will list “.” and “..”.
        echo .* *
fi

POSIX

모든 set옵션 을 저장하는 간단한 POSIX 호환 솔루션 은 다음과 같습니다.

set +o

POSIX 표준에 기술 로서 :

+ o

    현재 옵션 설정을 동일한 옵션 설정을 달성하는 명령으로 쉘에 다시 입력하기에 적합한 형식으로 표준 출력에 기록하십시오.

따라서 간단히 :

oldstate=$(set +o)

set명령을 사용하여 설정된 모든 옵션의 값을 유지합니다 .

다시, 옵션을 원래 값으로 복원하는 것은 변수를 실행하는 문제입니다.

set +vx; eval "$oldstate"

이것은 Bash를 사용하는 것과 정확히 같습니다 shopt -po. 이 옵션 중 일부는로 설정되어 있으므로 가능한 모든 Bash 옵션을 다루지 는 않습니다 .shopt

bash 특별한 경우

shoptbash 에는 다른 쉘 옵션이 많이 있습니다 .

$ shopt
autocd          off
cdable_vars     off
cdspell         off
checkhash       off
checkjobs       off
checkwinsize    on
cmdhist         on
compat31        off
compat32        off
compat40        off
compat41        off
compat42        off
compat43        off
complete_fullquote  on
direxpand       off
dirspell        off
dotglob         off
execfail        off
expand_aliases  on
extdebug        off
extglob         off
extquote        on
failglob        off
force_fignore   on
globasciiranges off
globstar        on
gnu_errfmt      off
histappend      on
histreedit      off
histverify      on
hostcomplete    on
huponexit       off
inherit_errexit off
interactive_comments    on
lastpipe        on
lithist         off
login_shell     off
mailwarn        off
no_empty_cmd_completion off
nocaseglob      off
nocasematch     off
nullglob        off
progcomp        on
promptvars      on
restricted_shell    off
shift_verbose   off
sourcepath      on
xpg_echo        off

그것들은 위의 변수 세트에 추가되고 같은 방식으로 복원 될 수 있습니다 :

$ oldstate="$oldstate;$(shopt -p)"
.
.                                   # change options as needed.
.
$ eval "$oldstate" 

할 수 있습니다 ( 보존 $-을 위해 추가됩니다 errexit).

oldstate="$(shopt -po; shopt -p); set -$-"

set +vx; eval "$oldstate"             # use to restore all options.

참고 : 각 쉘은 설정되거나 설정되지 않은 옵션 목록을 작성하는 방법이 약간 다르므로 (정의 된 다른 옵션은 말할 것도없고) 문자열은 쉘간에 이식 가능하지 않지만 동일한 쉘에 유효합니다.

zsh 특수 케이스

zsh버전 5.3 이후 (POSIX에 따라) 올바르게 작동합니다. 이전 버전에서는 POSIX set +o를 명령으로 쉘에 다시 입력하기에 적합한 형식으로 옵션을 인쇄했지만 설정 옵션 ( 설정되지 않은 옵션은 인쇄하지 않음) 으로 POSIX를 부분적으로 만 따랐 습니다 .

mksh 특수 케이스

mksh (및 결과적으로 lksh)는 아직이를 수행 할 수 없습니다 (MIRBSD KSH R54 2016/11/11). mksh 매뉴얼에는 다음이 포함됩니다.

이후 버전에서 set + o는 POSIX 호환 및 인쇄 명령을 사용하여 현재 옵션을 대신 복원합니다.

세트 -e 특별한 경우

bash에서 set -e( errexit) 값은 하위 셸 내에서 재설정되므로 set +o$ (…) 하위 셸 내에서 값을 캡처하기가 어렵습니다 .

해결 방법으로 다음을 사용하십시오.

oldstate="$(set +o); set -$-"

21

Almquist 쉘과 파생물 ( dash, NetBSD / FreeBSD sh이상) 및 bash4.4 이상을 사용하여 옵션을 함수에 로컬로 만들 수 있습니다 local -( $-원하는 경우 변수를 로컬로 설정).

$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace

즉 적용되지 않는 소스 파일,하지만 당신은 다시 정의 할 수 있습니다 sourcesource() { . "$@"; }그 해결하려면.

을 사용 ksh88하면 옵션 변경 사항이 기본적으로 함수에 로컬입니다. 함께 ksh93정의 기능 만 사건이, function f { ...; }구 (및 스코핑 정적 ksh88 포함한 다른 껍질에 사용되는 동적 범위 지정과 비교된다)

$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace

에서 zsh, 그것은 localoptions옵션으로 완료되었습니다 :

$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace

POSIXly, 당신은 할 수 있습니다 :

case $- in
  (*x*) restore=;;
  (*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace

그러나 일부 쉘은 + 2> /dev/null복원시 를 출력합니다 ( 이미 활성화 된 경우 해당 구문의 흔적 을 볼 수 있습니다). 이 접근 방식은 다시 입력 할 수 없습니다 (자신을 호출하는 함수 또는 동일한 트릭을 사용하는 다른 함수에서 수행하는 것처럼).caseset -x

이 문제를 해결하는 스택을 구현하는 방법 은 https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh(POSIX 셸의 변수 및 옵션에 대한 로컬 범위)를 참조 하십시오 .

어떤 쉘이든, 서브 쉘을 사용하여 옵션 범위를 제한 할 수 있습니다

$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace

그러나 이것은 옵션뿐만 아니라 모든 범위 (변수, 함수, 별칭, 리디렉션, 현재 작업 디렉토리 ...)의 범위를 제한합니다.


bash는 4.4 4 일 전 나온 (16 9 월 2016), 그래서 아마 당신은 스스로를 다시 컴파일해야하지만, 이유없는
edi9999

oldstate=$(set +o)모든 옵션을 저장하는 더 간단한 (및 POSIX) 방법 인 것 같습니다 .
sorontar

@sorontar, 그 그래도 좋은 점은 없습니다와 같은 쉘 구현 작업 수행 pdksh/ mksh(및 기타 pdksh 같은 유도체) 또는 zsh경우 set +o에만 기본 설정에서 편차를 출력합니다. bash / dash / yash에서는 작동하지만 이식성이 없습니다.
Stéphane Chazelas

13

$-처음에 변수를 읽고 -x설정 여부를 확인한 다음 변수에 저장할 수 있습니다. 예 :

if [[ $- == *x* ]]; then
  was_x_set=1
else
  was_x_set=0
fi

로부터 배쉬 설명서 :

($-, 하이픈) 호출시, set builtin 명령 또는 쉘 자체 (예 : -i 옵션)에 의해 지정된 현재 옵션 플래그로 확장됩니다.


7
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x

bash에서 $ SHELLOPTS 는 켜져있는 플래그로 설정됩니다. xtrace를 켜기 전에 확인하고 xtrace가 꺼져있는 경우에만 재설정하십시오.


5

set -x스크립트 지속 시간 동안 적용 되는 것이 명백한 경우 , 이는 일시적인 테스트 측정 일 뿐이며 (영구적으로 출력의 일부가 아님), -x옵션을 사용 하여 스크립트를 호출하십시오 ( 예 :

$ bash -x path_to_script.sh

... 또는 -x옵션 을 추가하여 디버그 출력을 사용하도록 스크립트 (첫 번째 줄)를 임시로 변경하십시오 .

#!/bin/bash -x
...rest of script...

나는 이것이 아마도 당신이 원하는 것에 비해 너무 광범위하다는 것을 알고 있지만, 어쨌든 (내 경험상) 제거하고 싶을 일시적인 것들로 스크립트를 지나치게 복잡하게 만들지 않고 가장 간단하고 가장 빠르게 활성화 / 비활성화하는 방법입니다.


3

POSIX $-특수 매개 변수를 통해 표시되는 플래그를 저장하고 복원하는 기능을 제공합니다 . local지역 변수에 대한 확장을 사용합니다 . POSIX 호환 휴대용 스크립트에서는 전역 변수가 사용됩니다 ( local키워드 없음 ).

save_opts()
{
  echo $-
}

restore_opts()
{
  local saved=$1
  local on
  local off=$-

  while [ ${#saved} -gt 0 ] ; do
    local rest=${saved#?}
    local first=${saved%$rest}

    if echo $off | grep -q $first ; then
      off=$(echo $off | tr -d $first)
    fi

    on="$on$first"
    saved=$rest
  done

  set ${on+"-$on"} ${off+"+$off"}
}

이것은 Linux 커널에서 인터럽트 플래그를 저장하고 복원하는 방법과 유사하게 사용됩니다.

Shell:                                Kernel:

flags=$(save_opts)                    long flags;
                                      save_flags (flags);

set -x  # or any other                local_irq_disable(); /* disable irqs on this core */

# ... -x enabled ...                  /* ... interrupts disabled ... */

restore_opts $flags                   restore_flags(flags);

# ... x restored ...                  /* ... interrupts restored ... */

$-변수 에서 다루지 않는 확장 옵션에는 작동하지 않습니다 .

POSIX에 내가 찾고있는 것이 있다는 것을 알았습니다. +o인수 set는 옵션이 아니라 eval-ed 인 경우 옵션을 복원 하는 많은 명령을 덤프하는 명령입니다 . 그래서:

flags=$(set +o)

set -x

# ...

eval "$flags"

그게 다야.

한 가지 작은 문제는이 -x옵션이이 옵션보다 먼저 바뀌면 eval추악한 set -o명령이 발생 한다는 것 입니다. 이를 제거하기 위해 다음을 수행 할 수 있습니다.

set +x             # turn off trace not to see the flurry of set -o.
eval "$flags"      # restore flags

1

서브 쉘을 사용할 수 있습니다.

(
   set 
   do stuff
)
Other stuff, that set does not apply to
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.