변수가 비어 있어도 test -n이 true를 반환하는 이유는 무엇입니까? 내가 뭘 잘못했나요? [복사]

변수가 비어 있어도 test -n이 true를 반환하는 이유는 무엇입니까? 내가 뭘 잘못했나요? [복사]

test(1)매뉴얼 페이지 에 따르면 :

       -n STRING
              the length of STRING is nonzero

그래서 나는 이것이 잘 작동할 것이라고 기대했습니다.

[ -n ${var} ] && echo "var is not empty"

이 로직을 실제 사례에서 사용했는데, 스크립트는 다음과 같습니다.

[...]
dne() {
    echo DEBUG: wc -c: $(echo -n $peopkg |wc -c)
    echo DEBUG: pdir: $pdir
    echo "Error: ${package}: doesn't exist in local repos"
    exit 1
}


# packages are listed as such: 
# p/pname/package-version-release-distrelease...
# pname is inconsistent, but it is guaranteed that the first word in package
# (all to lowercase) will match at least one pname.
# NOTE: package-[0-9]* matches package-32bit. *-32bit is a subpackage we want
# to match later, but not when it's not already in pcase.
# So that must be negated too

pfirst=${pcase%%-*}
for pdir in ${p}/${pfirst}*
do
    # check if the glob matched anything at all
    [ ${pdir} = "${p}/${pfirst}*" ] && dne

    peopkg=$(find ${pdir} \
        -name ${package}-[0-9]* \
        ! -name *.delta.eopkg \
        ! -name ${package}-32bit* |sort -rn |head -1)
    echo DEBUG: in-loop peopkg: $peopkg
    echo DEBUG: in-loop wc -c: $(echo -n $peopkg |wc -c)
    echo DEBUG: in-loop test -n: $(test -n $peopkg && echo true || echo false)
    #------------------------------------------------------------#
    # break on ANY match. There's supposed to be only one anyway #
    [ -n ${peopkg} ] && break # <--- [issue here]                #
    #------------------------------------------------------------#
done
[ -z ${peopkg} ] && dne
[...]

여기서 중요한 점은 실행하면 다음과 같은 메시지가 나타난다는 것입니다.

DEBUG: in-loop peopkg:
DEBUG: in-loop wc -c: 0
DEBUG: in-loop test -n: true
DEBUG: wc -c: 0
DEBUG: pdir: a/alsa-firmware
Error: alsa-utils: doesn't exist in local repos

이것은 나에게 이해가 되지 않습니다. DEBUG: pdir: a/alsa-firmware루프가 항상 첫 번째 반복에서 종료됨을 나타냅니다. 이는 glob 패턴 a/alsa*가 무언가와 일치하고 peopkg의 길이가 0이 아닌 경우에만 발생합니다.

추신: 저는 POSIX 호환성을 연구 중입니다.

답변1

var빈 문자열이 포함된 경우 ( [ -n $var ]토큰화 후 $var) 단어로 확장 됩니다 [. 이는 단일 매개변수가 null이 아닌지 테스트하는 의 단일 매개변수 버전입니다 . 문자열이 비어 있지 않으므로 테스트는 true입니다.-n]test-n

GNU 매뉴얼 페이지에서는 인용한 단락 뒤에 이 내용이 언급되어 있습니다.

   -n STRING
          the length of STRING is nonzero

   STRING equivalent to -n STRING

물론 문제는 인용이 부족하다는 것입니다.공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?그리고언제 큰따옴표가 필요합니까?

따옴표가 없으면 빈 문자열만 손상되는 것이 아닙니다. var여러 단어가 포함된 경우에도 문제가 발생할 수 있습니다.

$ var='foo bar'; [ -n $var ]
bash: [: foo: binary operator expected

또는 와일드카드:

$ var='*'; [ -n $var ]
bash: [: file.txt: binary operator expected

답변2

-n따옴표가 없는 변수에는 작동하지 않습니다.
맨페이지에 표시된 대로 -n0이 아닌 길이를 테스트합니다..
따라서 변수를 사용하여 null로 확장되는지 테스트할 때 변수를 참조해야 합니다.

그래서 이 문제의 해결책은[ -n "${peopkg}" ]

답변3

예, 비어 있지 않은 문자열이 없는 것 같습니다. 그러나 값에 공백이 있으므로 변수를 인용해야 합니다.

예를 들어

a="hello, world"
b=""

test -n "$a"
test -n "$b"

관련 정보