bash 산술 표현식의 null 또는 설정되지 않은 변수가 0으로 대체된다고 가정해도 안전합니까?

bash 산술 표현식의 null 또는 설정되지 않은 변수가 0으로 대체된다고 가정해도 안전합니까?

Bash 매뉴얼 페이지(버전 4.2)의 산술 평가 섹션에서 다음 설명을 발견했습니다.

null이거나 설정되지 않은 쉘 변수는 매개변수 확장 구문을 사용하지 않고 이름으로 참조할 때 0으로 평가됩니다.

고급 Bash 스크립팅 가이드에는 다음이 있습니다.페이지그리고 다음 댓글을 남겨주세요.

#  Bash (usually) sets the "integer value" of null to zero
#+ when performing an arithmetic operation.
#  But, don't try this at home, folks!
#  It's undocumented and probably non-portable behavior.

다음은 이 동작의 예입니다.

$ foo=
$ let 'foo += 5'
$ echo $foo
5
$ unset foo
$ let 'foo += 2'
$ echo $foo
2

bash가 null 변수를 0으로 대체한다고 가정해도 안전합니까? 이로 인해 bash 버전 간에 코드를 이식할 수 없게 된다고 가정해 보겠습니다.

답변1

예, 산술 확장은 에서 차용되었으며 bash80년대 이후 ksh문서화된 방식이었습니다 .ksh

그러나 POSIX 산술 확장에서는 십진수 상수가 포함되지 않는 한( , 및 는 괜찮지만 빈 문자열이든 아니든) $((x * 2))동작이 (POSIX에 의해) 지정되지 않습니다 . 이는 POSIX 스크립트 Assumptions 에서 이 작업을 수행할 수 없음을 의미합니다 .$x2-21+1sh

또한 참고하세요(적어도 에서는 bash):kshzsh

$ echo $((2*$foo-2)) # actually $((2*-2))
-4
$ echo $((2*foo-2))  # actually $((2*0-2))
-2

답변2

~에서수동:

null이거나 설정되지 않은 쉘 변수는 매개변수 확장 구문을 사용하지 않고 이름으로 참조할 때 0으로 평가됩니다.

pdksh, ksh93, dash 및 zsh처럼 이것이 변경되었다는 사실을 알지 못하지만 POSIX는 동작을 지정하지 않습니다.

if set -o nounset(aka set -u)가 작동 $((a))하거나 설정되지 않은 경우 오류가 발생한다는 점에 유의하세요 ((a+=1))(bash 및 ksh93에서는, dash, pdksh 또는 zsh에서는 제외).a

또한 이는 $((a+1))매개변수 대체를 사용할 때는 작동하지 않고 산술 표현식에서 직접 매개변수를 사용할 때만 작동합니다 $(($a+1)). 비교:

$ unset a
$ echo $((1 - a + 2))   # 1 - 0 + 2
3
$ echo $((a - $a + 2))  # 1 - (+2)
-1

답변3

합리적으로 새로운 시스템에서는 bash가 null 변수를 0으로 대체한다고 가정하는 것이 안전합니다.

bash 4.2의 맨페이지에 문서화된 것처럼 이는 적어도 해당 버전에 대한 문서화된 동작임은 확실합니다. 고급 Bash 스크립팅 가이드에 설명된 대로(문서화되지는 않음), 이 동작은 이 가이드가 작성된 당시 사용 가능한 모든 버전의 Bash에서 예상할 수 있습니다. 아마도 bash의 초기 버전으로 돌아갈 것입니다.

그러나 절대적으로 엄격해지려면 지원하려는 모든 bash 버전에 대한 문서를 확인해야 하며 동작이 명시적으로 문서화되지 않은 버전에 대해서는 어떤 가정도 할 수 없습니다.

절대적으로 엄격할 필요는 없다고 생각하지만 위험을 감수하고 싶지 않다면 foo=${foo:-0}정의되지 않은 변수를 사용하기 전에 명시적으로 0으로 설정할 수 있습니다. 예:

foo=1

foo=${foo:-0}
bar=${bar:-0}

echo "before math: foo=$foo, bar=$bar"
let 'foo += 2'
let 'bar += 2'
echo "after math: foo=$foo, bar=$bar"

산출:

before math: foo=1, bar=0
after math: foo=3, bar=2

관련 정보