nounset shell 옵션을 사용하여 버전 4.2 이전의 Bash에서 변수가 전혀 정의되어 있는지 테스트하는 방법은 무엇입니까?


16

"GNU bash, 버전 4.2"이전의 Bash 버전 -v의 경우 test명령 옵션에 대한 동등한 대안이 있습니까? 예를 들면 다음과 같습니다.

shopt -os nounset
test -v foobar && echo foo || echo bar
# Output: bar
foobar=
test -v foobar && echo foo || echo bar
# Output: foo

-v의 옵션이 test아니라 조건식 연산자입니다.
StackExchange for

@Tim 토큰, 문자열 및 줄의 일부가 아닌 세 가지입니다 : An optionto a command test -v, a operatorto a conditional expressionand unary test primaryfor [ ]. 영어와 쉘 정의를 혼용하지 마십시오.

답변:


36

모든 POSIX 쉘에 이식 가능 :

if [ -n "${foobar+1}" ]; then
  echo "foobar is defined"
else
  echo "foobar is not defined"
fi

확인 ${foobar:+1}당신이 취급 할 경우 foobar같은 방식으로 비어 여부를 정의인지. 정의되지 않은 경우 및 그렇지 않은 ${foobar-}경우 빈 문자열을 얻는 데 사용할 수도 있습니다 (또는 뒤에 다른 기본값을 넣습니다 ).foobarfoobar-

ksh에서 if foobar와 같이 선언되었지만 정의되지 않은 경우 빈 문자열 typeset -a foobar${foobar+1}확장됩니다.

Zsh에는 선언되었지만 설정되지 않은 변수가 없습니다 typeset -a foobar. 빈 배열을 만듭니다.

bash에서 배열은 다른 놀라운 방식으로 동작합니다. 비어 있지 않은 배열 인 경우 ${a+1}에만 확장1a

typeset -a a; echo ${a+1}    # prints nothing
e=(); echo ${e+1}            # prints nothing!
f=(''); echo ${f+1}          # prints 1

동일한 배열이 연관 배열에 적용됩니다. 배열 변수는 비어 있지 않은 인덱스 집합이있는 경우 정의 된대로 처리됩니다.

모든 유형의 변수가 정의되었는지 여부를 테스트하는 다른 bash 특정 방법은에 나열되어 있는지 확인하는 것입니다 . 이렇게하면 빈 배열이 정의 된대로 보고되지만 선언되었지만 할당되지 않은 변수 ( )는 정의되지 않은 것으로보고합니다.${!PREFIX*}${foobar+1}unset foobar; typeset -a foobar

case " ${!foobar*} " in
  *" foobar "*) echo "foobar is defined";;
  *) echo "foobar is not defined";;
esac

이는 선언되었지만 할당되지 않은 변수에서 실패하는 것을 제외하고 또는 의 반환 값typeset -p foobardeclare -p foobar테스트하는 것과 같습니다 typeset -p foobar.

ksh에서와 같이 bash에서는 set -o nounset; typeset -a foobar; echo $foobar정의되지 않은 변수를 확장하려는 시도에서 오류가 발생합니다 foobar. ksh와 달리 set -o nounset; foobar=(); echo $foobar(또는 echo "${foobar[@]}")도 오류를 트리거합니다.

여기에 설명 된 모든 상황에서 아래에 오류가 발생하는 ${foobar+1}경우에만 빈 문자열로 확장 $foobar됩니다 set -o nounset.


1
배열은 어떻습니까? Bash 버전 "GNU bash, 버전 4.1.10 (4)-릴리스 (i686-pc-cygwin)" 는 이전에 발행 된 경우 echo "${foobar:+1}"인쇄되지 않으므로 인덱스 배열입니다. 올바르게보고합니다 . 비 배열 변수에만 작동 합니까 ? 1declare -a foobarfoobardeclare -p foobardeclare -a foobar='()'"${foobar:+1}"
Tim Friske

“defined”에 대한 정의가“”에서 작동하는 경우 @TimFriske ${foobar+1}( :, 내 원래 답변에 두 가지 예를 거꾸로 뒤집어 놓았습니다 )가 bash의 배열에 적합합니다 . 정의가 다르면 bash는 약간 이상합니다. 업데이트 된 답변을 참조하십시오. $foobarset -o nounset
Gilles 'SO- 악마 그만해

1
bash에서 "배열에서 배열은 다르게 놀라운 방식으로 동작합니다." 동작은 bash (1) 맨 페이지의 "배열"섹션에서 설명 할 수 있습니다. "아래 첨자가없는 배열 변수를 참조하는 것은 아래 첨자가 0 인 배열을 참조하는 것과 같습니다." 도 따라서 경우 0가 그렇듯이 인덱스 나 키가 정의되고 a=(), ${a+1}올바르게 아무 것도 반환하지 않습니다.
Tim Friske

1
@TimFriske bash 구현이 해당 설명서를 준수한다는 것을 알고 있습니다. 그러나 빈 배열을 정의되지 않은 변수처럼 취급하는 것은 실제로 이상한 디자인입니다.
Gilles 'SO- 악한 중지

Bash에 변수가 설정되어 있는지 확인하는 방법 은 다음과 같은 결과를 선호합니다 . -> 올바른 길 ... 나는 이것이 어떻게 작동 해야하는지 에 대해 화음을 친다 . 감히, Windows에는 defined운영자가 있습니다. 그것을 Test 할 수 있었다 ; 그것은 (어려울 수 없습니다 ....)
됩니다

5

Gilles의 답변과 요약하면 다음 규칙을 구성했습니다.

  1. [[ -v foobar ]]Bash 버전> = 4.2의 변수에 사용하십시오 .
  2. declare -p foobar &>/dev/nullBash 버전 <4.2의 배열 변수에 사용하십시오 .
  3. 사용 (( ${foo[0]+1} ))또는 (( ${bar[foo]+1} ))(인덱스의 첨자 -a) 및 키가 ( -A) 배열 ( declare각각). 옵션 1과 2는 여기서 작동하지 않습니다.

3

bash의 모든 변수에 동일한 기술을 사용하며 다음과 같이 작동합니다.

[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

출력 :

foobar is unset

...하는 동안

foobar=( "val" "val2" )
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

출력 :

foobar is set

배열에 둘 이상의 값이 있으면 [@]를 제거해야합니다.
Stein Inge Morisbak

1
값이 정의되어 있는지 여부가 아니라 값이 있는지 테스트하려는 경우에 효과적입니다. 즉, foobar=""그런 다음보고합니다 foobar is unset. 잠깐만 요. 실제로 첫 번째 요소가 비어 있는지 여부를 테스트하기 때문에 변수가 배열이 아니라는 것을 알고 정의가 아닌 공허함 만 신경 쓰면 좋은 생각 인 것 같습니다.
Ron Burk 2016 년

정의되지 않은 변수가 허용 된 상태에서 스크립트가 실행중인 경우에만 작동합니다 (-u 없음)
Florian Heigl
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.