Bash에서 길이가 0이 아닌 문자열을 테스트하십시오. [-n "$ var"] 또는 [ "$ var"]


182

Bash 스크립트가 두 가지 방법으로 길이가 0이 아닌 문자열을 테스트하는 것을 보았습니다. 대부분의 스크립트는 다음 -n옵션을 사용합니다 .

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

그러나 -n 옵션은 실제로 필요하지 않습니다.

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

어느 쪽이 더 좋은 방법입니까?

마찬가지로 길이가 0 인 테스트를위한 더 좋은 방법입니다.

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

또는

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi

답변:


394

편집 : 이것은 [(일명 test)과 ( 와)의 차이점을 더 보여주는 더 완전한 버전입니다 [[.

다음 표는 변수의 인용 여부, 단일 또는 이중 괄호 사용 여부 및 변수에 공백 만 포함되는지 여부는 테스트를 사용하거나 사용하지 않고 -n/-z변수를 확인하는 데 적합한 지 여부에 영향을주는 요소를 보여줍니다 .

     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b
     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"
-----+------------------------------------+------------------------------------
unset| false false true  false true  true | false false false false true  true
null | false false true  false true  true | false false false false true  true
space| false true  true  true  true  false| true  true  true  true  false false
zero | true  true  true  true  false false| true  true  true  true  false false
digit| true  true  true  true  false false| true  true  true  true  false false
char | true  true  true  true  false false| true  true  true  true  false false
hyphn| true  true  true  true  false false| true  true  true  true  false false
two  | -err- true  -err- true  -err- false| true  true  true  true  false false
part | -err- true  -err- true  -err- false| true  true  true  true  false false
Tstr | true  true  -err- true  -err- false| true  true  true  true  false false
Fsym | false true  -err- true  -err- false| true  true  true  true  false false
T=   | true  true  -err- true  -err- false| true  true  true  true  false false
F=   | false true  -err- true  -err- false| true  true  true  true  false false
T!=  | true  true  -err- true  -err- false| true  true  true  true  false false
F!=  | false true  -err- true  -err- false| true  true  true  true  false false
Teq  | true  true  -err- true  -err- false| true  true  true  true  false false
Feq  | false true  -err- true  -err- false| true  true  true  true  false false
Tne  | true  true  -err- true  -err- false| true  true  true  true  false false
Fne  | false true  -err- true  -err- false| true  true  true  true  false false

변수의 길이가 0이 아닌지 확인하려면 다음 중 하나를 수행하십시오.

  • 단일 괄호로 변수를 인용하십시오 (열 2a)
  • -n단일 괄호로 변수를 사용 하고 인용하십시오 (열 4a)
  • 인용 부호가 있거나없는 이중 열 괄호 사용 -n(열 1b-4b)

"2"로 표시된 행에서 시작하는 열 1a에서 결과는 변수 [내용 이 마치 조건식의 일부인 것처럼 평가하고 있음을 나타냅니다 (결과는 설명 열). [[를 사용 하면 (열 1b) 변수 내용이 문자열로 표시되고 평가되지 않습니다.

열 3a 및 5a의 오류는 변수 값에 공백이 포함되고 변수의 인용 부호가 없기 때문에 발생합니다. 다시 3 열과 5b 열에 표시된 것처럼 [[변수의 내용을 문자열로 평가합니다.

이에 따라 길이가 0 인 문자열에 대한 열 6a, 5b 및 6b는 올바른 방법을 보여줍니다. 부정이 반대 연산을 사용하는 것보다 분명한 의도를 나타내는 경우 이러한 테스트 중 하나라도 부정 할 수 있습니다. 예를 들면 다음과 같습니다 if ! [[ -n $var ]]..

을 사용하는 경우 [예기치 않은 결과가 발생하지 않도록하는 열쇠는 변수를 인용하는 것입니다. 를 사용하면 [[중요하지 않습니다.

억제되는 오류 메시지는 "단항 연산자 예상"또는 "이진 연산자 예상"입니다.

위의 테이블을 생성 한 스크립트입니다.

#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal

dw=5    # description column width
w=6     # table column width

t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }

o=/dev/null

echo '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'
echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'
echo '-----+------------------------------------+------------------------------------'

while read -r d t
do
    printf '%-*s|' "$dw" "$d"

    case $d in
        unset) unset t  ;;
        space) t=' '    ;;
    esac

    [ $t ]        2>$o  && t || f
    [ "$t" ]            && t || f
    [ -n $t ]     2>$o  && t || f
    [ -n "$t" ]         && t || f
    [ -z $t ]     2>$o  && t || f
    [ -z "$t" ]         && t || f
    echo -n "|"
    [[ $t ]]            && t || f
    [[ "$t" ]]          && t || f
    [[ -n $t ]]         && t || f
    [[ -n "$t" ]]       && t || f
    [[ -z $t ]]         && t || f
    [[ -z "$t" ]]       && t || f
    echo

done <<'EOF'
unset
null
space
zero    0
digit   1
char    c
hyphn   -z
two     a b
part    a -a
Tstr    -n a
Fsym    -h .
T=      1 = 1
F=      1 = 2
T!=     1 != 2
F!=     1 != 1
Teq     1 -eq 1
Feq     1 -eq 2
Tne     1 -ne 2
Fne     1 -ne 1
EOF

1
감사! "단일 괄호 (열 2a)로 변수 인용"IMO 스타일을 채택하기로 결정했습니다. -n은 노이즈를 추가하고 가독성을 떨어 뜨립니다. 마찬가지로 길이가 0이거나 설정되지 않은 테스트의 경우에는 [! [-z "$ var"] 대신 "$ var"].
AllenHalsey

2
따라서 (OP의 첫 번째 질문) ["vs에 대한 차트 [-n"는 완전히 동일하다는 것을 보여줍니다.
호브

1
@ hobs : 예, 어느 것이 더 명확한 지에 따라 다릅니다. 또한 이중 대괄호 형식을 사용할 때 Bash를 사용할 때 선호되는 것과 동등한 것을 알 수 있습니다.
추후 공지가있을 때까지 일시 중지되었습니다.

1
따라서 멋진 테이블을 요약하면 null이 아닌 문자열을 테스트하는 더 명확한 ( "더 나은") 방법은 다음과 같습니다.[["
호브

22

Bash에 관한 한 더 강력한 것을 사용하는 것이 좋습니다 [[.

일반적인 경우

if [[ $var ]]; then   # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string

위의 두 구성은 깨끗하고 읽기 가능해 보입니다. 대부분의 경우 충분합니다.

단어 분할globbing의[[ 위험이 없으므로 변수 확장을 인용 할 필요 가 없습니다 .

방지하기 위해 shellcheck을 '에 대한 소프트 불만이야 [[ $var ]]하고 [[ ! $var ]], 우리가 사용할 수있는 -n옵션을 선택합니다.

드문 경우

"빈 문자열로 설정"과 "전혀 설정하지 않음"을 구분해야하는 드문 경우에는 다음을 사용할 수 있습니다.

if [[ ${var+x} ]]; then           # var is set but it could be empty
if [[ ! ${var+x} ]]; then         # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty

-v테스트를 사용할 수도 있습니다 .

if [[ -v var ]]; then             # var is set but it could be empty
if [[ ! -v var ]]; then           # var is not set
if [[ -v var && ! $var ]]; then   # var is set and is empty
if [[ -v var && -z $var ]]; then  # var is set and is empty

관련 게시물 및 문서

이 주제와 관련된 게시물이 많이 있습니다. 몇 가지가 있습니다 :


9

몇 가지 테스트가 더 있습니다.

문자열이 비어 있지 않은 경우 참 :

[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"

문자열이 비어 있으면 참 :

[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"

이것은 더 나은 방법에 대한 OP의 질문에 대답하지 않습니다.
codeforester

0

정답은 다음과 같습니다.

if [[ -n $var ]] ; then
  blah
fi

의 사용을 참고 [[...]]올바르게에 대한 변수를 인용 처리합니다.


2
-nBash에서 실제로 필요하지 않은 이유는 무엇 입니까?
codeforester

0

빈 환경 변수를 평가하는 대안적이고 아마도 더 투명한 방법은 다음을 사용하는 것입니다.

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi

10
이것은 본 쉘 시대의 아주 오래된 학교입니다. 이 오래된 습관을 영속하지 마십시오. bash이전 모델보다 더 날카로운 도구입니다.
tbc0

2
POSIX 표준이 명시 적으로 더 이상 사용되지 않는 구문을 피하는 경우 사전 bash 쉘에서는 이것을 필요로하지 않습니다. bash뿐만 아니라 ash / dash / ksh / etc 와 같은 POSIX 호환 구현 [ "$ENV_VARIABLE" != "" ]으로 모든 쉘에서 작동합니다 test.
Charles Duffy

... 사용하지 않는 말을 인 -a또는 -o검사를 결합 대신 사용 [ ... ] && [ ... ]하거나 [ ... ] || [ ... ]명확하게 닫혀 테스트에서 임의 변수의 데이터를 사용하여 적용 할 수있는 유일한 코너 케이스를합니다.
Charles Duffy

-2

case/esac테스트에 사용 :

case "$var" in
  "") echo "zero length";;
esac

12
아니요 괜찮아요. 이것은 case의도 된 것이 아닙니다 .
tbc0

2
case두 개 이상의 대안이있을 때 가장 잘 작동합니다.
codeforester

case이런 종류의 사용을위한 것이 아닙니다.
Luis Lavaire 19 :
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.