패턴 일치를 위한 POSIX 문서설명하다:
일반 문자는 자신과 일치하는 패턴입니다. NUL, 인용해야 하는 Quoting의 특수 셸 문자 및 다음 세 가지 특수 패턴 문자를 제외한 지원되는 문자 집합의 모든 문자가 될 수 있습니다. 일치는 문자의 그래픽 표현이 아니라 문자를 인코딩하는 데 사용되는 비트 패턴을 기반으로 해야 합니다.문자(일반, 쉘 특수 또는 패턴 특수)가 인용된 경우 패턴은 문자 자체와 일치해야 합니다.. 쉘 특수 문자에는 항상 따옴표가 필요합니다.
내가 아는 한 패턴은 및 중 하나와 ["!"a]
일치합니다 . 이는 및 다음을 제외하고 내가 시도한 대부분의 쉘의 동작이기도 합니다 .!
a
zsh
ksh93
$ for shell in /bin/*[^c]sh; do
printf '=%-17s=\n' "$shell"
"$shell" -c 'case a in ["!"a]) echo 1;; esac'
done
=/bin/ash =
1
=/bin/bash =
1
=/bin/dash =
1
=/bin/heirloom-sh =
1
=/bin/ksh =
=/bin/lksh =
1
=/bin/mksh =
1
=/bin/pdksh =
1
=/bin/posh =
1
=/bin/schily-osh =
1
=/bin/schily-sh =
1
=/bin/yash =
1
=/bin/zsh =
zsh
와 같은 ksh93
것 같습니다 . 다음을 제외한 모든 문자와 일치합니다 .["!"a]
[!a]
a
$ for shell in ksh93 zsh; do
printf '=%-6s=\n' "$shell"
"$shell" -c 'case b in ["!"a]) echo 1;; esac'
done
=ksh93 =
1
=zsh =
1
zsh
여기에는 어떤 이유가 있나요(역사, 발전...) ksh93
?
zsh
ksh
에뮬레이션과 에뮬레이션 모두에서 동일한 작업을 수행합니다 sh
.
busybox sh
, Solaris /usr/xpg4/bin/sh
및 FreeBSD sh
도 POSIX 문서와 유사하게 작동합니다.
ksh88
또한 대부분의 다른 쉘과 마찬가지로 동작은 kssh88
다음 사이에서 변경됩니다 ksh93
.
$ ksh88 -c 'case a in ["!a"]) echo yes; esac'
yes
$ ksh88 -c 'case b in ["a-c"]) echo yes; esac'
$
답변1
당신이 인용한 구절은 당신이 말한 것을 의미하지 않습니다.
단일 문자와 일치하는 패턴
(…) 일반 문자는 자신과 일치하는 패턴입니다. (…) 문자(일반, 쉘 특수 또는 패턴 특수)가 인용되면 패턴은 문자 자체와 일치해야 합니다.
이 모든 것은 패턴에서 자신을 나타내는 문자에만 적용됩니다. 이는 예상되는 패턴 문자 이외의 컨텍스트에 나타나는 문자에는 적용되지 않습니다. 특히 괄호 표현식 내에서는 작동하지 않습니다. 대괄호 표현식의 구문은 다음 항목 아래에 설명되어 있습니다 [
.
열린 괄호가 다음과 같이 괄호 표현식을 도입하는 경우XBD RE 브래킷 표현, (…)
!
(vs.에 대한 부분은 생략하고 추가했습니다 ^
.) RE 대괄호 표현식에 대한 설명은 인용에 대해 아무 말도 하지 않습니다. (쉘 스크립트의 패턴이 아니라 일반적인 대괄호 표현식에 관한 것이기 때문에 놀라운 것은 아닙니다.) 대괄호 표현).
["!"a]
POSIX.1-2008의 엄격한 해석에 따르면 패턴이 무엇과 일치해야 하는지 명확하지 않습니다 . 한 가지 해석은 모든 문자 와 일치해야 한다는 것입니다 "
. 문자는 대괄호 표현식에서 특별한 의미가 없습니다. 사양에서 이 해석을 무효화하는 내용을 찾을 수 없습니다. 또 다른 해석은 인용 동작이 유지된다는 것입니다. 그러나 이는 대괄호 표현식의 내용이 임을 의미하며 , 대괄호 표현식 내의 인용 문자에 대한 특별한 처리가 없으므로 집합은 all-but-입니다 . POSIX 사양에서는 귀하의 해석(그리고 dash, bash 및 기타 셸의 동작)에 대한 지원을 찾을 수 없습니다. 물론 이것은 의미가 있지만 그렇지 않습니다.!
a
"
"
!a
a
POSIX의 향후 버전에서는 일부 문구를 추가하여 해석을 강제하는 것이 합리적입니다. 예를 들어 설명은 [
다음과 같이 변경될 수 있습니다.
열린 괄호가 다음과 같이 괄호 표현식을 도입하는 경우XBD RE 브래킷 표현단, 정규식 표기법에서 \ 문자( ) 는 일치하지 않는 목록에서 \ 문자( )의 역할을
'!'
대체해야 하며 패턴 대괄호 표현식을 도입해야 합니다.'^'
, 인용된 문자는 그 자체를 대괄호 표현식, 대조 요소 또는 클래스 표현식의 요소로 나타냅니다.. 따옴표가 없는 \ 문자로 시작하는 대괄호 표현식은 지정되지 않은 결과를 생성합니다. 그렇지 않으면'['
문자 자체가 일치해야 합니다.
POSIX가 규범적이기보다는 주로 설명적이라는 점을 감안할 때 ksh(일반적으로 참조 셸)를 손상시키는 이와 같은 변경 사항은 표준의 주요 업데이트에만 포함될 것이며 기존 버전의 모든 결함은 최소한 기존 버전이 허용할 것으로 예상합니다. 다르게 설명해주세요.
답변2
이는 버그이며 zsh
이 토론에서 보고되었습니다.[버그] 브래킷 모드 내의 참조는 효과가 없습니다.:
case b in
( ['a-c'] ) echo 'false match' ;;
( [a-c] ) echo 'correct match' ;;
esac
false match
대신 인쇄됩니다 correct match
.
복원 계획은 다음과 같습니다.zsh
버전 5.3으로 출시됨.
답변3
당신이 읽고 있는 내용은 단순한 문자에만 적용됩니다. 안에 문자가 없습니다 Bracket expression
.
실제로 이전에도 매우 명확하게 밝혀졌습니다.
따옴표가 없고 대괄호 표현식 외부에 있는 경우 다음 세 문자는 패턴 사양에서 특별한 의미를 갖습니다.
? <물음표> ...
* <별표> ...
[ 여는 괄호가 대괄호 표현식을 도입하는 경우...
무엇Bracket Expression
당신은 여기를 읽어야합니다.
사양에 따르면 "대괄호 표현" 내부에는 참조(패턴에 대한) 개념이 없습니다.
그러나 대부분의 쉘은 문자열이 "대괄호 표현식" 안에 있더라도 문자열에서 따옴표를 제거합니다. 이것이 바로 a가 명령이 ["!"a]
된 이유입니다.[!a]
그러나 쉘은 문자열에 대한 지식을 유지합니다.예전에는대부분의 쉘은 인용되어 있으므로 부정은 효과가 없습니다("대괄호 표현" 내에서 인용하지 않는다는 사양의 개념과 반대).
ksh 및 zsh에서는 이 지식이 모드를 평가하는 데 사용되지 않습니다.
왜 이런 일이 발생합니까? 나는 이것이 단지 오류라고 믿습니다.
그러나 ksh와 zsh는 대부분의 쉘과 다르게 동작합니다.
다음 코드를 사용하십시오(모든 쉘의 모든 값을 테스트하려면 사례를 반복하십시오).
whichsh="`ps -o pid,args| awk '$1=='"$$"'{print $2}'`"
[ ${whichsh##*/} = zsh ] && setopt GLOB_SUBST
[ ${whichsh##*/} = zsh4 ] && setopt GLOB_SUBST
a="$1"; printf '%s\t' "testing $a"
case $a in ['!a']) printf 1 ;; esac
case $a in ["!a"]) printf 2 ;; esac
case $a in ['!'a]) printf 3 ;; esac
case $a in ["!"a]) printf 4 ;; esac
case $a in [\"!\"a]) printf 5 ;; esac
case $a in [!a]) printf 6 ;; esac
printf "\t --"
t1="['!a']";t2='["!a"]';t3="['!'a]";t4='["!"a]';t5='[\"!\"a]'
case $a in $t1) printf 1 ;; esac
case $a in $t2) printf 2 ;; esac
case $a in $t3) printf 3 ;; esac
case $a in $t4) printf 4 ;; esac
case $a in $t5) printf 5 ;; esac
case $a in [!a]) printf 6 ;; esac
echo
"a"를 사용한 테스트의 경우 ./script.sh a
결과는 다음과 같습니다.
/bin/dash : testing a 12345 --12345
/bin/sh : testing a 12345 --12345
/bin/b43sh : testing a 12345 --12345
/bin/b44sh : testing a 12345 --12345
/bin/bash : testing a 12345 --12345
/bin/ksh : testing a 5 --12345
/bin/ksh93 : testing a 5 --12345
/bin/lksh : testing a 12345 --12345
/bin/mksh : testing a 12345 --12345
/bin/zsh : testing a 5 --12345
/bin/zsh4 : testing a 5 --12345
"b"를 테스트하면 ./script.sh b
결과는 다음과 같습니다.
/bin/dash : testing b 6 --6
/bin/sh : testing b 6 --6
/bin/b43sh : testing b 6 --6
/bin/b44sh : testing b 6 --6
/bin/bash : testing b 6 --6
/bin/ksh : testing b 12346 --6
/bin/ksh93 : testing b 12346 --6
/bin/lksh : testing b 6 --6
/bin/mksh : testing b 6 --6
/bin/zsh : testing b 12346 --6
/bin/zsh4 : testing b 12346 --6
테스트 모드에서 변수 내에 따옴표가 있으면 따옴표가 제거되지 않고 결과에 영향을 줍니다. ksh 및 zsh는 따옴표를 제거하고 패턴에서 직접 사용할 때 따옴표를 평가합니다 [!a]
.
쉘이 해야 할 일은 테스트 문자의 일부로 대괄호 안에 따옴표를 유지하는 것입니다.
"인용된" 인용문을 얻으려면 ksh와 zsh에 유사한 패턴이 필요합니다 [\"!\"a]
. 그러면 둘 다 a
, !
및 와 일치합니다 "
.