쉘 옵션을 수정하고 복원하는 방법에 대한 다양한 스택 교환 사이트와 유닉스 도움말 포럼에서 많은 질문을 읽었습니다. 여기서 찾은 가장 포괄적인 질문은 다음과 같습니다.`set -x`를 "실행 취소"하는 방법은 무엇입니까?
이것지혜를 얻다이전 설정을 저장했다가 나중에 복원한 결과 set +o
인 것 같습니다 .shopt -po
eval
그러나 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는 errexit
POSIX 모드에서 실행될 때 유지됩니다. 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
완벽한.