내 질문은 다음에서 비롯됩니다.쉘 변수에 정규식을 저장하여 쉘 특정 문자를 인용하는 문제를 피하는 방법은 무엇입니까?.
오류가 발생하는 이유:
$ [[ $a = a|b ]] bash: syntax error in conditional expression: unexpected token `|' bash: syntax error near `|b'
[[ ... ]]
두 번째 피연산자는 내부적으로=
와일드카드 패턴일 것으로 예상됩니다.a|b
유효한 와일드카드 패턴이 아닙니까 ? 어떤 문법 규칙을 위반하는지 지적할 수 있나요?아래의 일부 주석은
|
파이프로 해석됨을 나타냅니다.그런 다음
=
glob 모드를=~
정규식 모드 로 변경하여|
작동하게 합니다.$ [[ $a =~ a|b ]]
나는 그것으로부터 배웠다학습 난교p180인치내 이전 게시물
|
다른 해석 단계(예제의 조건식 구문 분석 포함) 이전에도 해석 시작 시 파이프로 인식됩니다. 그렇다면|
사용될 때 정규식 연산자로 인식되지만=~
잘못 사용될 때는 파이프로 인식되지 않게 하려면 어떻게 해야 합니까=
? 이로 인해 파트 1의 구문 오류가|
파이프로 해석되는 것은 아니라는 생각이 들었습니다 .쉘이 표준 입력 또는 스크립트에서 읽는 각 행은 파이프라고 하며 0개 이상의 파이프 문자(|)로 구분된 하나 이상의 명령을 포함합니다. 읽는 각 파이프에 대해 쉘은 이를 명령으로 나누고 파이프의 I/O를 설정한 후 각 명령에 대해 다음을 수행합니다(그림 7-1).
감사해요.
답변1
정당한 이유는 없어
[[ $a = a|b ]]
$a가 문자열인지 테스트하는 대신 오류가 보고되어야 하며 a|b
while은 [[ $a =~ a|b ]]
오류를 반환하지 않습니다.
유일한 이유는 |
일반적으로 (외부적으로나 내부적으로 [[ ... ]]
) 특수 문자이기 때문입니다. 해당 [[ $a =
위치 에는 bash
일반 토큰 유형이 필요합니다.단어일반 쉘 명령줄의 인수 또는 리디렉션 대상과 같습니다(그러나 extglob
bash 4.1부터 옵션이 활성화된 것처럼).
(통과단어여기요, 내 말은단어다음과 같은 가상의 쉘 구문에서POSIX 사양에 설명된 유형, 쉘은 영어 문자 시퀀스 또는 공백이 아닌 문자 시퀀스와 같은 다른 단어 정의가 아닌 간단한 쉘 명령줄의 토큰으로 이를 구문 분석합니다. foo"bar baz"
, $(echo x y)
, 이거 2개야단어에스).
일반 쉘 명령줄에서:
echo a|b
.not a echo a
로 파이프됨b
a|b
단어, 이는 세 개의 마크입니다:a
단어, |
토큰 및b
단어토큰.
사용될 때 [[ $a = a|b ]]
, bash
기대하십시오단어( )을 얻었 a
으나 예상치 못한 |
토큰을 발견하여 오류가 발생합니다.
흥미롭게도 bash
불만 사항은 없었습니다.
[[ $a = a||b ]]
이제 a
토큰, ||
토큰, 또 다른 토큰이 있으므로 b
다음과 같은 방식으로 구문 분석됩니다.
[[ $a = a || b ]]
문자열이 $a
비어 있는지 테스트합니다.a
b
지금:
[[ $a =~ a|b ]]
bash
동일한 구문 분석 규칙을 가질 수 없습니다. 동일한 구문 분석 규칙을 사용하면 위의 오류가 발생하며 규칙 이 단일인지 |
확인하기 위해 규칙을 참조해야 함을 의미합니다.a|b
단어. 그러나 bash 3.2부터 시작하면 다음과 같습니다.
[[ $a =~ 'a|b' ]]
a|b
이는 더 이상 정규식 일치를 위한 것이 아닙니다 a\|b
. 즉, 쉘 인용은 정규식 연산자의 특별한 의미를 제거하는 부작용이 있습니다. 이것은 기능이므로 동작은 [[ $a = "?" ]]
이와 유사하지만 와일드카드 패턴( 에서 사용됨 [[ $a = pattern ]]
)은 셸입니다.성격(예: glob에 사용됨) 정규 표현식의 경우에는 해당되지 않습니다.
bash
따라서 일반적으로 와 같은 특수 셸 문자인 모든 확장 정규식 연산자는 |
연산자 인수를 구문 분석할 때 다르게 처리되어야 합니다 (
.)
=~
그러나 참고하시기 바랍니다.
[[ $a =~ (ab)*c ]]
지금 유효합니다.
[[ $a =~ [)}] ]]
아니요. 다음을 수행해야 합니다.
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
이전 버전에서는 bash
백슬래시가 잘못 일치했습니다. 이 문제는 해결되었지만
[[ $a =~ [^]')'] ]]
하다아니요예를 들어, 백슬래시를 일치시키십시오. 괄호 안에 bash
있다는 것을 알 수 있는 방법이 없기 때문에 이스케이프를 수행하면 , 및 를 제외한 모든 문자와 일치하는 정규식이 생성됩니다 .)
)
[^]\)]
]
\
)
ksh93
이와 관련하여 더 심각한 오류가 있습니다.
에서는 zsh
일반 쉘 단어이므로 정규식 연산자를 인용해도 정규식 연산자의 의미에 영향을 주지 않습니다.
[[ $a =~ 'a|b' ]]
정규식과 일치합니다 a|b
.
이는 / 명령 =~
에도 추가할 수 있음을 의미합니다 .[
test
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(..에서도 사용할 수 있습니다. 특별한 쉘 연산자가 있으므로 yash
as로 인용해야 합니다 .)=~
zsh
=something
bash 3.1은 유사하게 동작했습니다 . 3.2에서는 아마도 ( 첫 번째 쉘 제안에도 불구하고 ) zsh
일관성을 유지하기 위해 변경되었지만 여전히 이전 동작을 실행 하거나 되돌릴 수 있습니다( 3.1에서 오류를 반환하는 경우 는 제외). 최신 버전에서 작동합니다) .ksh93
bash
[[ =~ ]]
BASH_COMPAT=31
shopt -s compat31
[[ $a =~ a|b ]]
bash
bash -O compat31
bash
내가 이 규칙이 혼란스럽다고 말한 이유와 다음을 사용하는 이유가 명확해지기를 바랍니다.
[[ $a =~ $var ]]
다른 쉘을 포함한 이식성에 도움이 됩니다.
답변2
표준 glob("파일 이름 확장자")은 다음과 같습니다. *
및 ?
. [ ... ]
는 |
표준(비extglob) 설정에서 유효한 glob 연산자가 아닙니다.
노력하다:
shopt -s extglob
[[ a = @(a|b) ]] && echo matched
답변3
정규식 일치를 원할 경우 테스트는 다음과 같습니다.
[[ "$a" =~ a|b ]]