zsh -z는 "+x"의 의미를 테스트합니다.

zsh -z는 "+x"의 의미를 테스트합니다.

저는 zsh를 처음 접했고 수년간 bash 사용자였습니다.

예제 zsh 스크립트에서 테스트를 볼 수 있습니다.

if [ ! -z ${ZSH_MOTD_CUSTOM+x} ]; then

Bash에서는 다음을 기대합니다.

if [ ! -z "$ZSH_MOTD_CUSTOM" ]; then

zsh 예제와 bash에 적용되는 경우 +x의 의미를 이해하지 못합니다.

답변1

${var+string}Bourne 쉘(1970년대 후반부터) 및 모든 POSIX 쉘(bash 포함)과 동일한 연산자입니다. zsh 문서에서 해당 설명을 찾을 수 있습니다 info zsh 'Parameter Expansion'.

${NAME+WORD}
${NAME:+WORD}
설정된 경우 대체 NAME되거나 두 번째 형식에서 null이 아닌 WORD경우 대체되는 항목이 없습니다.

거기에서 찾기가 더 어렵지만 info bash 'Parameter Expansion'거기에서도 마찬가지입니다. 의 경우 sh확인할 수 있습니다.POSIX 사양(단, bash 매뉴얼처럼 ${parameter:+word}1에서 콜론을 생략한 효과를 언급한 문장에 주의할 필요가 있습니다.)

Bash 및 기타 Bourne 유사 쉘과의 주요 차이점은 인용 해제가 분할+glob의 영향을 받지 않는다는 것입니다 . 왜냐하면 ${ZSH_MOTD_CUSTOM+x}zsh에서는 인수 확장 시 IFS 분할 및/또는 글로빙을 수행하려는 경우 명시적으로 요청해야 하기 때문입니다. $=var, $~var와일드카드(엄격히 말하면 내용을 $var패턴으로 처리) 의 $=~var경우 둘 다 다른 쉘과 동일합니다 $var.

그러나 참조되지 않은 확장은 여전히 ​​null로 삭제되므로 이는 잘못된 것입니다. 그러나 이 경우 우연히 그것은 문제가 되지 않을 것이며 아마도 저자가 작동하지 않는 [ ! -z $expansion ]대신 그것을 쓰기로 선택한 이유일 것입니다.[ -n $expansion ]

if가 비어 있으면( $expansionif가 설정되지 않은 경우) not이 되므로 확장자가 비어 있지 않은지 테스트하지 않지만 자체가 빈 문자열인지 테스트하므로(분명히 그렇지 않습니다) 잘못된 결과로 인한 오류를 구현하여 올바른 결과를 얻습니다(변수가 설정되었는지 테스트).${ZSH_MOTD_CUSTOM+x}$ZSH_MOTD_CUSTOM[ ! -z $expansion ][ ! -z ][ ! -z '' ]-z

Bash에서 인용되지 않은 내용은 ${ZSH_MOTD_CUSTOM+x}분할+glob의 영향을 받으므로 버그가 더 많지만 빈 문자열이나 리터럴로만 확장되므로 다음 x을 포함하는 경우에만 문제가 발생합니다.$IFSx

$ bash -xc 'IFS=y; [ ! -z ${HOME+x} ]; echo "$?"'
+ IFS=y
+ '[' '!' -z x ']'
+ echo 0
0
$ bash -xc 'IFS=x; [ ! -z ${HOME+x} ]; echo "$?"'
+ IFS=x
+ '[' '!' -z '' ']'
+ echo 1
1
$ zsh -xc 'IFS=x; [ ! -z ${HOME+x} ]; echo "$?"'
+zsh:1> IFS=x
+zsh:1> [ ! -z x ']'
+zsh:1> echo 0
0

이것모든 POSIX 셸의 올바른 구문할 것이다:

if [ -n "${ZSH_MOTD_CUSTOM+x}" ]

이는 Bourne 셸에서도 작동합니다. 확장은 빈 문자열만 가능하기 때문에 ... 와 같은 [ -n "$var" ]값에서는 실패합니다 (따라서 고대 구현에는 문제가 있는 문자열이 없습니다 ).$var=-gtx[

이제 zsh에는 변수가 설정되었는지 확인하는 보다 관용적인 방법이 있습니다. 예를 들면 다음과 같습니다.

if (( $+ZSH_MOTD_CUSTOM ))

if가 설정된 경우 $+var로 확장되고 , 그렇지 않은 경우로 확장 됩니다 .1$var0

또는:

if [[ -v ZSH_MOTD_CUSTOM ]]

À la ksh (bash에서도 발견됨).

어쨌든 [ ! -z "$ZSH_MOTD_CUSTOM" ]작성하는 방법 자체는 복잡하지만 [ -n "$ZSH_MOTD_CUSTOM" ]다른 작업을 수행합니다. 즉, 변수가 설정되었는지 여부에 관계없이 변수가 null이 아닌지 확인합니다. 가장 큰 차이점은 $ZSH_MOTD_CUSTOM설정된 경우 false를 반환하지만 null을 반환한다는 것입니다. 변형과 달리 변수가 설정되지 않고 ${ZSH_MOTD_CUSTOM+x}옵션이 활성화된 경우에도 오류가 발생합니다.nounset

$ zsh -c 'if [ -n "$foo" ]; then echo non-empty; else echo empty; fi'
empty
$ foo= zsh -o nounset -c 'if [ -n "$foo" ]; then echo non-empty; else echo empty; fi'
empty
$ foo= zsh -o nounset -c 'if [ -n "${foo+x}" ]; then echo set; else echo unset; fi'
set
$ zsh -o nounset -c 'if [ -n "$foo" ]; then echo non-empty; else echo empty; fi'
zsh:1: foo: parameter not set
$ zsh -o nounset -c 'if [ -n "${foo+x}" ]; then echo set; else echo unset; fi'
unset
$ zsh -o nounset -c 'if [ -n "${foo-}" ]; then echo non-empty; else echo empty; fi'
empty

(마지막에서는 ${foo-}동일한 것으로 확장되지만 $foo(a.k.a.) 효과를 피하는 것을 사용합니다.)nounsetset -u


1 이 기능이 존재하는 Bourne 쉘에서는 처음에는( 1970년대 후반 Unix 버전 7 ) 콜론이 없는 버전만 지원되었고 나중에는 콜론이 있는 버전이 지원되었습니다.시스템 III에서.

답변2

이는 Bash에도 존재하는 매개변수(변수) 확장 구문입니다. 이는 아마도 대부분의 다른 Bourne 스타일 쉘에서도 마찬가지일 것입니다. 귀하의 예에서 zsh의 유일한 특별한 점은 테스트되는 변수입니다.

Bash 매뉴얼 페이지에서 우리는 두 가지를 볼 수 있습니다. 이 확장 구문에 대한 설명:

  ${parameter:+word}
    Use Alternate Value. If parameter is null or unset, nothing is substituted,
    otherwise the expansion of word is substituted.

몇 문단 전, 확장 구문 섹션 상단에 많은 사람들이 간과하는 내용이 있습니다.

  When not performing substring expansion, using the forms documented below
  (e.g., :-),  bash  tests for a parameter that is unset or null.  Omitting
  the colon results in a test only for a parameter that is unset.

마지막 문장이 관련 부분입니다. Omitting the colon results in a test only for a parameter that is unset. 이를 설명하기 위해 매뉴얼 페이지에 제공된 구문은 다음과 같습니다.

  ${parameter:+word}

콜론을 생략하면 다음과 같습니다.

  ${parameter+word}

차이점은 후자 구문에서 반환되는 값이 다음과 같다는 것입니다.단어변수가 설정되지 않은(존재하지 않는) 경우를 제외하고 모든 경우에 적용됩니다. 따라서 zsh 스크립트에 표시되는 구문은 다음과 같습니다.

  ${ZSH_MOTD_CUSTOM+x}

x$ZSH_MOTD_CUSTOM정의된 경우 (값에 관계없이 - 빈 문자열 포함) 반환 하지만 변수가 정의되지 않은 경우 빈 문자열을 반환합니다.

마지막으로 스크립트 예제는 포함된 값에 관계없이 변수가 존재하는지 여부만 테스트합니다. 나는 Bash 매뉴얼 페이지를 인용하여 답변하고 있습니다. 왜냐하면 당신은 이전 bash 사용자였으며 bash 설명이 친숙할 것이라고 언급했기 때문입니다.

이것은 내가 (아주 오랫동안) 경력을 쌓으면서 본 Bourne 스타일 쉘 스크립트에서 흔히 볼 수 있는 관용어가 아니기 때문에 :-많은 사람들이 이에 대해 알지 못합니다. 나 자신도 최근에야 알게 되었습니다.:=:?:+:

답변3

test이는 zsh 변수 확장으로 인한 것이 아닙니다 .

설정된 경우 이 생성자가 ${foo+bar}반환됩니다.bar$foo

예를 들면 다음과 같습니다.

zsh% unset foo
zsh% echo ${foo+bar}

zsh% foo=
zsh% echo ${foo+bar}
bar

관련 정보