shopt
함수의 옵션 값을 일시적으로 변경하고 싶습니다 .
내장 함수를 사용하여 설정할 수 있는 옵션은 함수 본문 내에서 설정할 set
수 있습니다. local -
아래는 샘플 코드입니다
#!/bin/bash
# Enable the options globally
set -u
[[ "$SHELLOPTS" =~ nounset ]] && echo "1: nounset enabled"
shopt -s "extglob"
[[ "$BASHOPTS" =~ extglob ]] && echo "1: extglob enabled"
fun () {
#Enable the options locally just in fun
local -
# local BASHOPTS
set +u
[[ "$SHELLOPTS" =~ nounset ]] || echo "2: nounset disabled"
shopt -u "extglob"
[[ "$BASHOPTS" =~ extglob ]] || echo "2: extglob disabled"
}
fun
if [[ "$SHELLOPTS" =~ nounset ]]; then
echo "3: nounset enabled"
else
echo "3: nounset disabled"
fi
if [[ "$BASHOPTS" =~ extglob ]]; then
echo "3: extglob enabled"
else
echo "3: extglob disabled"
fi
출력 포함
1: nounset enabled
1: extglob enabled
2: nounset disabled
2: extglob disabled
3: nounset enabled
3: extglob disabled
보시다시피 옵션은 nounset
함수 본문에 추가하는 것만으로 지역화할 수 있습니다. local -
나는 동일한 shopt
옵션을 원합니다. 현재 해결 방법은 먼저 옵션이 활성화되어 있는지 확인하는 것입니다.
if ! shopt -q extglob; then
extglobchanged=1
shopt -s extglob
fi
그런 다음 마침내 이전 상태로 다시 변경합니다.
[[ "$extglobchanged" == 1 ]] && shopt -u extglob
중간 코드가 실패할 수 있는 모든 상황을 처리해야 하기 때문에 이는 좋은 해결책이 아닙니다. (함수가 종료되기 전에 위 줄이 실행되는지 확인해야 합니다.)
질문:
옵션을 현지화할 수 있나요 shopt
?
--편집 1--
동기 부여
내 bash 툴킷에는 사용자에게 예 또는 아니오를 쿼리하는 기능이 있습니다. 나는 case
패턴을 or와 연결하기 위해 이 목적으로 확장된 glob을 사용합니다. 이게 내 코드야
yesnoquery () {
local extglobchanged=0
local returnvalue=2
while true; do
if read -p "$1" answer; then
if ! shopt -q extglob; then
extglobchanged=1
shopt -s extglob #enable for pattern matching
fi
eval '
case "$answer" in
@([Yy]|[Yy][Ee][Ss])) returnvalue=0;; #true
@([Nn]|[Nn][Oo])) returnvalue=1;; #false
* ) echo "Please answer \"y\" or \"n\"";;
esac
'
[[ "$extglobchanged" == 1 ]] && shopt -u extglob #revert changes
[[ "$returnvalue" != 2 ]] && return "$returnvalue"
else
return 2 #reading returned error
fi
done
}
이런 사소한 일을 하기에는 오랜 시간이 걸리는 것 같습니다. shopt
옵션 extglob을 지역화할 수 있으면 case
like에서 직접 반환 할 수 있습니다 @([Yy]|[Yy][Ee][Ss])) return 0;;
. 또한 이 [[ "$extglobchanged" == 1 ]]...
줄과 그 뒤의 줄은 필요하지 않습니다 .
주요 문제
현재는 함수가 종료될 수 있는 모든 위치에 변경 사항을 되돌리려면 수동으로 코드를 추가해야 합니다 shopt
.
내 생각은 이러한 변경 사항을 현지화해야 한다는 것입니다 local -
. 현지화가 없는 다른 솔루션이 완벽할 것입니다.
이것이 단지 언어 제한이라면 이것이 내 질문에 대한 답이기도 합니다.
답변1
예, 가능합니다:
fun()
{
local -
# store state of all options.
oldstate="$(shopt -p)"
:
:
set +vx; eval "$oldstate"
}
특별한 상황이 있습니다 errexit
.
답변2
내 필요에 맞는 솔루션을 찾은 것 같습니다.서브셸에서 함수 본문 실행. 서브셸에서 함수 본문을 실행하는 것의 장점과 단점은 물론 일반적인 사용 사례도 여기에서 여러 번 논의되었습니다.[1][2][삼].
에서 언급했듯이[4]Bash man
페이지에서 가져온 함수의 일반 구문은 다음과 같습니다.
[ function ] name () compound-command [redirection]
A는 Compound comamand
괄호 구문을 사용하여 시작된 현재 쉘의 하위 프로세스일 수 있습니다 (list)
. man bash
다음과 같이 정의하십시오(강조 추가):
(list) list 서브셸 환경에서 실행합니다(아래 명령 실행 환경 참조). 변수 할당 및 내장 명령쉘에 영향을 미치는 환경완료 후에는 명령이 더 이상 유효하지 않습니다. 반환 상태는 목록의 종료 상태입니다.
내 사용 사례에는 두 가지가 필요합니다.
shopt
옵션 변경의 현지화 효과extglob
.- 반품 상태 유지
서브쉘로 인한 shopt
옵션 변경 사항은 extglob
주변 쉘로 유출되지 않습니다. 또한 함수의 어느 지점에서든 반환할 수 있습니다. 물론 단점은 서브셸을 시작하는 데 추가 리소스가 필요하다는 것입니다.
데모
이제 더 짧은 함수는 다음과 같습니다.
yesnoquery () (
while true; do
if read -p "$1" answer; then
shopt -s extglob
eval '
case "$answer" in
@([Yy]|[Yy][Ee][Ss]) ) return 0;; #true
@([Nn]|[Nn][Oo]) ) return 1;; #false
* ) echo "Please answer \"yes\" or \"no\"";;
esac
'
else
return 2 #reading returned error
fi
done
)
Case 문에서 이제 임시 변수에 저장하는 대신 직접 반환할 수 있습니다. 지역화된 변수는 더 이상 필요하지 않으며 두 조건이 모두 저장되었습니다.
shopt
이러한 옵션이 실제로 로컬이라는 것은 문제의 코드 샘플 코드에서 빠르게 확인할 수 있습니다.
#!/bin/bash
# Enable the options globally
set -u
[[ "$SHELLOPTS" =~ nounset ]] && echo "1: nounset enabled"
shopt -s "extglob"
[[ "$BASHOPTS" =~ extglob ]] && echo "1: extglob enabled"
fun () {
set +u
[[ "$SHELLOPTS" =~ nounset ]] || echo "2: nounset disabled"
shopt -u "extglob"
[[ "$BASHOPTS" =~ extglob ]] || echo "2: extglob disabled"
}
fun
if [[ "$SHELLOPTS" =~ nounset ]]; then
echo "3: nounset enabled"
else
echo "3: nounset disabled"
fi
if [[ "$BASHOPTS" =~ extglob ]]; then
echo "3: extglob enabled"
else
echo "3: extglob disabled"
fi
변경된 것은 모두 여기에 있는 괄호 (
( {
및 제거된 중복 지역 변수)입니다. 산출
1: nounset enabled
1: extglob enabled
2: nounset disabled
2: extglob disabled
3: nounset enabled
3: extglob enabled
효과가 성공적으로 타겟팅되었음을 나타냅니다.
일반화하다
함수 본문으로서의 서브쉘 실행 환경은 bash 쉘 옵션의 효과를 지역화하는 데 유용한 것으로 입증되었습니다. 이 변수를 변경해도 함수 범위 외부의 코드에는 영향을 주지 않기 때문에 case
함수 본문 내부의 명령문은 이로부터 이점을 얻을 수 있습니다 . extglob
리소스가 부족한 경우 하위 셸을 시작하는 데 따른 추가 오버헤드로 인해 성능이 불필요하게 느려질 수 있습니다.