Bash 셸 스크립트에 문자열이 정의되어 있지 않은지 확인하는 방법


151

null 문자열을 확인하고 싶다면

[ -z $mystr ]

그러나 변수가 정의되어 있는지 확인하려면 어떻게해야합니까? 아니면 Bash 스크립팅에 차이가 없습니까?


27
[-z $ mystr]과 달리 [-z "$ mystr"] 사용 습관을들이십시오
Charles Duffy

반대로하는 방법? 문자열이 널 (null)이 아닌 경우 내 말은
열기를 길

1
@flow : 어떻습니까[ -n "${VAR+x}"] && echo not null
Lekensteyn

1
@CharlesDuffy 나는 많은 온라인 자료에서 이것을 읽었습니다. 왜 이것이 선호됩니까?
ffledgling

6
@Ayos 따옴표가 없으면 변수의 내용이 문자열 분할되어 붙잡기 때문입니다. 빈 문자열이면 [ -z ]대신에 [ -z "" ]; 공백이 있으면 [ -z "my" "test" ]대신 공백이 됩니다 [ -z my test ]. 그것의 경우 [ -z * ], 다음은 *디렉토리에있는 파일의 이름으로 대체됩니다.
Charles Duffy

답변:


138

Vinko답변에 따르면 당신이 따르는 대답은 암시되어 있지만 (단, 명시되지 않은 경우) 단순히 철자가 아닙니다. VAR이 설정되었지만 비어 있는지 여부를 구별하려면 다음을 사용할 수 있습니다.

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

두 번째 줄의 두 테스트를 다음과 함께 하나로 결합 할 수 있습니다.

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

그러나 Autoconf에 대한 설명서를 읽으면 용어를 ' -a'와 함께 사용하지 않는 것이 좋으며와 함께 별도의 간단한 테스트를 사용하는 것이 좋습니다 &&. 문제가있는 시스템을 발견하지 못했습니다. 그렇다고 그들이 존재하지 않았 음을 의미하지는 않습니다 (그러나 먼 과거에 희귀하지 않았더라도 요즘에는 극히 희귀합니다).

Bash 매뉴얼에서 이들에 대한 세부 사항과 기타 관련 쉘 매개 변수 확장 , test또는[ 명령 및 조건식을 찾을 수 있습니다 .


나는 최근에 다음과 같은 질문에 대한 답을 이메일로 받았다.

두 가지 테스트를 사용하고 두 번째 테스트는 잘 이해하지만 첫 번째 테스트는 이해하지 못합니다. 더 정확하게는 변수 확장의 필요성을 이해하지 못합니다

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi

이것이 동일하게 달성되지 않습니까?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

공정한 질문-대답은 '아니요, 더 간단한 대안은 같은 것을하지 않습니다'입니다.

테스트 전에 이것을 작성한다고 가정 해보십시오.

VAR=

테스트에는 "VAR이 전혀 설정되어 있지 않습니다"라고 표시되지만 "VAR이 설정되었지만 값이 비어있을 수 있습니다"라는 메시지가 나타납니다. 이 스크립트를 사용해보십시오 :

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

출력은 다음과 같습니다.

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

두 번째 테스트 쌍에서는 변수가 설정되지만 비어있는 값으로 설정됩니다. 이것이 ${VAR=value}${VAR:=value}표기법 의 구별입니다 . 동감 ${VAR-value}하고 ${VAR:-value},과 ${VAR+value}${VAR:+value}등.


Gili 가 그의 대답 에서 지적한 것처럼 bash, set -o nounset옵션으로 실행 하면 위의 기본 대답이 실패합니다 unbound variable. 쉽게 해결됩니다.

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

또는 ( 와 같음 ) 으로 set -o nounset옵션을 취소 할 수 있습니다.set +uset -uset -o nounset


7
이 답변에 대한 유일한 문제는 다소 간접적이고 명확하지 않은 방식으로 작업을 수행한다는 것입니다.
Swiss

3
bash 맨 페이지에서 위의 의미에 대한 설명을 찾으려면 "매개 변수 확장"섹션을 찾은 다음이 텍스트를 참조하십시오. "하위 문자열 확장을 수행하지 않는 경우 아래 문서화 된 양식을 사용하여 bash 테스트 unset 또는 null [빈 문자열을 의미하는 'null'] 매개 변수 콜론을 생략하면 설정되지 않은 매개 변수에 대해서만 테스트가 수행됩니다 (...) $ {parameter : + word} : 대체 값 사용. "이 (가) null이거나 설정되지 않은 경우 대체되는 것이 없습니다. 그렇지 않으면 단어 확장이 대체됩니다."
David Tonhofer

2
@Swiss 이것은 불분명하거나 간접적이지 않지만 관용적입니다. 아마와 프로그래머 익숙에 ${+}${-}는 불분명하지만, 하나는 쉘의 유능한 사용자로하는 경우 그 구조에 대한 지식은 필수적이다.
William Pursell

이를 활성화 하여 구현하려면 stackoverflow.com/a/20003892/14731을 참조하십시오 set -o nounset.
길리

나는 이것에 대해 많은 테스트를했다; 내 스크립트의 결과가 일관성이 없기 때문입니다. bash -s v4.2 이상 에서 " [ -v VAR ]"접근 방식을 살펴 보는 것이 좋습니다 .
것입니다

38
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z는 정의되지 않은 변수에도 적용됩니다. 정의되지 않은 정의와 정의되지 않은 정의를 구별하려면 여기에 나열된 내용을 사용 하거나 더 명확한 설명과 함께 here을 사용 하십시오 .

가장 깨끗한 방법은이 예제와 같이 확장을 사용하는 것입니다. 모든 옵션을 얻으려면 매뉴얼의 파라미터 확장 섹션을 확인하십시오.

다른 단어 :

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

기본값:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

물론 이들 중 하나를 다르게 사용하여 '기본값'대신 원하는 값을 넣고 적절한 경우 확장을 직접 사용합니다.


1
그러나 문자열이 ""인지 또는 정의되지 않은지를 구별하고 싶습니다. 가능합니까?
Setjmp

1
이 답변 이 두 경우를 구별하는 방법을 알려줍니다. 자세한 내용은 bash faq 링크를 참조하십시오.
Charles Duffy

1
나는 찰스, 그의 코멘트 후 그 추가
Vinko Vrsalovic

2
이 모든 "트릭"에 대해서는 bash 매뉴얼 페이지에서 "Parameter Expansion"을 찾으십시오. 예 : $ {foo : -default}는 기본값을 사용하고 $ {foo : = default}는 기본값을 지정하고 $ {foo :? error message}는 foo가 설정되지 않은 경우 오류 메시지를 표시합니다.
Jouni K Seppänen

18

고급 bash 스크립팅 안내서, 10.2. 매개 변수 대체 :

  • $ {var + blahblah} : var가 정의 된 경우 'blahblah'가 표현식으로 대체되고, 그렇지 않으면 null이 대체됩니다.
  • $ {var-blahblah} : var이 정의 된 경우 var 자체가 대체되고 그렇지 않은 경우 'blahblah'가 대체됩니다
  • $ {var? blahblah} : var이 정의되어 있으면 대체되고, 그렇지 않으면 오류 메시지로 'blahblah'가있는 함수가 존재합니다.


변수 $ mystr의 정의 여부에 따라 프로그램 논리를 작성하려면 다음을 수행하십시오.

isdefined=0
${mystr+ export isdefined=1}

이제 isdefined = 0이면 변수가 정의되지 않은 것이고 isdefined = 1이면 변수가 정의 된 것입니다.

변수를 검사하는 이러한 방법은 위의 답변보다 우수하고 읽기 쉽고, 정의되지 않은 변수를 사용할 때 bash 쉘이 오류로 구성되어 있으면 (set -u)스크립트가 조기에 종료됩니다.


다른 유용한 것들 :

정의되지 않은 경우 $ mystr에 기본값 7을 지정하고 그렇지 않으면 그대로 두십시오.

mystr=${mystr- 7}

변수가 정의되지 않은 경우 오류 메시지를 인쇄하고 함수를 종료하려면 다음을 수행하십시오.

: ${mystr? not defined}

$ mystr의 내용이 정의 된 경우 명령으로 실행되지 않도록 ':'을 사용했다는 것을 명심하십시오.


나는 몰랐다? BASH 변수 구문. 좋은 소식입니다.
Swiss

이것은 간접 변수 참조에서도 작동합니다. 이것은 다음을 통과 var= ; varname=var ; : ${!varname?not defined}하고 종료됩니다 : varname=var ; : ${!varname?not defined}. 그러나 set -u훨씬 쉬운 일 을하는 것이 좋은 습관 입니다.
ceving

11

테스트 요약.

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"

bash에서 좋은 연습. 때때로 파일 경로에 공백이 있거나 명령 삽입을 방지하기 위해
k107

1
내가 가진 생각 ${var+x}이 변수의 경우를 제외하고 필요하지 않습니다 이름이 그들에 공백을 가질 수 있습니다.
Anne van Rossum

좋은 연습뿐만 아니라; 것 필요[정확한 결과를 얻을 수 있습니다. 경우 var해제 또는 비어 [ -n $var ]로 감소 [ -n ]하면서, 어떤 종료 상태 0을 가지고 [ -n "$var" ]1의 예상 (정정) 종료 상태가
chepner

5

https://stackoverflow.com/a/9824943/14731 더 나은 답변 (더 읽기 쉽고 set -o nounset활성화 된 답변)이 포함되어 있습니다 . 대략 다음과 같이 작동합니다.

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi

4

정의되는 변수를 확인하는 명시적인 방법은 다음과 같습니다.

[ -v mystr ]

1
bash 또는 테스트 용 매뉴얼 페이지에서 이것을 찾을 수는 없지만 저에게 효과적입니다. 어떤 버전이 추가되었는지 아십니까?
Ash Berlin-Taylor

1
그것은에 설명되어 있습니다 조건식 으로부터 참조, test섹션의 꼬리 끝에서 운영자 Bourne 쉘 내장 명령 . 언제 추가되었는지는 모르겠지만 Apple 버전 bash( bash3.2.51 기반 )에는 없으므로 4.x 기능 일 수 있습니다.
Jonathan Leffler

1
이것은 나를 위해 작동하지 않습니다 GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu). 오류는 -bash: [: -v: unary operator expected입니다. 코멘트 당 여기 에서 작동하려면 최소한 bash 4.2가 필요합니다.
Acumenus

사용 가능해 졌는지 확인해 주셔서 감사합니다. 이전에 다양한 시스템에서 사용했지만 갑자기 작동하지 않았습니다. 나는 호기심으로 여기에 왔으며, 물론이 시스템의 배쉬는 3.x 배쉬입니다.
clacke

1

또 다른 옵션 : "목록 배열 색인"확장 :

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

이것이 빈 문자열로 확장되는 유일한 시간 foo은 설정 되어 있지 않으므로 문자열 조건부로 확인할 수 있습니다.

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

bash 버전> = 3.0에서 사용할 수 있어야합니다.


1

이 자전거를 더 흘리지 않고 추가하고 싶었습니다.

shopt -s -o nounset

스크립트 상단에 추가 할 수있는 변수 로, 스크립트에서 변수를 선언 하지 않으면 오류가 발생합니다 . 당신이 볼 수있는 메시지는 unbound variable이지만 다른 사람들이 언급했듯이 빈 문자열이나 null 값을 포착하지 않습니다. 개별 값이 비어 있지 않도록하기 위해 ${mystr:?}달러 기호 확장이라고도하는로 확장 된 변수를 테스트하면 오류가 발생합니다 parameter null or not set.


1

배쉬 참조 설명서 의 bash에 대한 정보의 권위있는 소스입니다.

변수가 존재하는지 확인하는 예제는 다음과 같습니다.

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

( 섹션 6.3.2 부터 )

열기 후 [및 앞에 있는 공백 ]선택 사항아닙니다 .


Vim 사용자를위한 팁

다음과 같이 몇 가지 선언이있는 스크립트가있었습니다.

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

그러나 나는 그들이 기존의 가치를 미루기를 원했다. 그래서 다음과 같이 다시 작성했습니다.

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

빠른 정규식을 사용하여 vim에서 이것을 자동화 할 수있었습니다.

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

관련 행을 시각적으로 선택한 다음을 입력하여 적용 할 수 있습니다 :. 명령 모음은로 미리 채워집니다 :'<,'>. 위의 명령을 붙여 넣고 Enter 키를 누르십시오.


이 버전의 Vim에서 테스트했습니다.

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by root@apple.com

Windows 사용자는 다른 줄 끝을 원할 수 있습니다.


0

변수가 정의되어 있는지 확인하는 훨씬 명확한 방법이라고 생각합니다.

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

다음과 같이 사용하십시오.

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi

1
함수를 작성하는 것은 나쁜 생각이 아닙니다. 호출 grep이 끔찍합니다. 이름이 지정된 변수의 값을 얻는 방법 을 bash지원 하므로 yield가 됩니다. ${!var_name}$var_namename=value; value=1; echo ${name} ${!name}value 1
Jonathan Leffler

0

정의되지 않은 변수를 테스트하는 짧은 버전은 다음과 같습니다.

test -z ${mystr} && echo "mystr is not defined"

-3

인수없이 호출 세트 .. 정의 된 모든 변수를 출력합니다.
목록의 마지막 항목은 스크립트에 정의 된 것입니다.
따라서 정의 된 내용과 그렇지 않은 내용을 파악할 수있는 결과로 파이프 출력을 파이프 할 수 있습니다 .


2
나는 이것을 투표하지 않았지만, 약간 작은 너트를 깨는 것은 망치의 일종이다.
Jonathan Leffler

나는 실제로이 대답이 허용되는 대답보다 낫습니다. 이 답변에서 수행중인 작업이 분명합니다. 받아 들여진 대답은 지옥처럼 기이합니다.
Swiss

이 답변은 바람직한 것보다 "세트"구현의 부작용에 더 가깝습니다.
Jonathan Morgan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.