errexit를 포함한 모든 쉘 옵션을 저장하고 복원하는 방법

errexit를 포함한 모든 쉘 옵션을 저장하고 복원하는 방법

쉘 옵션을 수정하고 복원하는 방법에 대한 다양한 스택 교환 사이트와 유닉스 도움말 포럼에서 많은 질문을 읽었습니다. 여기서 찾은 가장 포괄적인 질문은 다음과 같습니다.`set -x`를 "실행 취소"하는 방법은 무엇입니까?

이것지혜를 얻다이전 설정을 저장했다가 나중에 복원한 결과 set +o인 것 같습니다 .shopt -poeval

그러나 bash 3.x 및 4.x를 사용한 자체 테스트에서는 errexit명령 대체를 수행할 때 옵션이 올바르게 저장되지 않았습니다.

다음은 문제를 보여주는 샘플 스크립트입니다.

set -o errexit
set -o nounset
echo "LOCAL SETTINGS:"
set +o
OLDOPTS=$(set +o)
echo
echo "SAVED SETTINGS:"
echo "$OLDOPTS"

및 출력(관련 없는 변수를 일부 제거했습니다):

LOCAL SETTINGS:
set -o errexit
set -o nounset

SAVED SETTINGS:
set +o errexit
set -o nounset

이것은 매우 위험해 보입니다. 내가 작성하는 대부분의 스크립트는 errexit명령이 실패할 경우 실행을 중지하는 데 의존합니다. 방금 내 스크립트 중 하나에서 이로 인해 발생한 버그를 발견했습니다. 결국 복원되어야 했던 함수가 errexit이를 덮어쓰게 되어 다시 기본값으로 설정되었습니다.떠나다스크립트가 진행되는 동안.

내가 하고 싶은 것은 필요에 따라 옵션을 설정한 다음 복원할 수 있는 함수를 작성하는 것입니다.모두종료하기 전에 옵션을 올바르게 선택하십시오. 하지만 명령 치환에 의해 호출되는 서브쉘에서는 errexit상속될 수 없는 것 같습니다.

set +o명령 대체를 사용하거나 FIFO 링을 점프하지 않고 결과를 저장하는 방법을 모르겠습니다 . 읽을 수는 있지만 $SHELLOPTS쓸 수 없거나 사용할 수 없는 형식입니다 eval.

대안은 다음을 사용하는 것입니다.서브쉘 기능, 그러나 이로 인해 출력을 기록하고 여러 변수를 다시 전달하는 데 많은 문제가 발생합니다.

아마도 관련이 있을 것입니다:https://stackoverflow.com/questions/29532904/bash-subshell-errexit-semantics(bash 4.4 이상에 대한 해결 방법이 있는 것 같지만 휴대용 솔루션을 선호합니다)

답변1

당신이 하고 있는 일은 효과가 있을 것입니다. 그러나 bash는 명령 대체에서 해당 옵션을 끄므로 errexit그 옵션을 제외한 모든 것을 유지합니다. 이는 bash에 따라 다르며 errexit옵션에 따라 다릅니다. Bash는 errexitPOSIX 모드에서 실행될 때 유지됩니다. bash 4.4부터 bash는 errexit명령 대체에서 유효한지 여부를 지우지 않습니다 shopt -s inherit_errexit.

이 옵션은 명령 대체 내에서 코드가 실행되기 전에 꺼지기 때문에 외부에서 확인해야 합니다.

OLDOPTS=$(set +o)
case $- in
  *e*) OLDOPTS="$OLDOPTS; set -e";;
  *) OLDOPTS="$OLDOPTS; set +e";;
esac

이러한 복잡성이 마음에 들지 않으면 대신 zsh를 사용하십시오.

setopt local_options

답변2

알파인 3.6에서 위의 이전 방법을 시도한 후 이제 다음과 같은 더 간단한 방법을 채택했습니다.

OLDOPTS="$(set +o); set -${-//c}"
set -euf -o pipefail

... my stuff

# restore original options
set +vx; eval "${OLDOPTS}"

문서에 따르면 "$-"는 현재 활성화된 옵션 목록을 보유하고 있습니다. 잘 작동하는 것 같은데, 제가 뭔가를 놓치고 있는 걸까요?

답변3

errexit프로세스 교체로 전파됩니다.

set -e

# Backup restore commands into an array
declare -a OPTS
readarray -t OPTS < <(shopt -po)

set +e

# Restore options
declare cmd
for cmd in "${OPTS[@]}"; do
    eval "$cmd"
done

확인하다:

$  shopt -po errexit
set -o errexit

히트 버전:

$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

답변4

간단한 해결책은 errexit설정을 다음에 추가하는 것입니다 OLDOPTS.

OLDOPTS="$(set +o)"
[ "${BASH_VERSION:+x}" ] && shopt -qo errexit && OLDOPTS+=";set -e" || true

완벽한.

관련 정보