전역 모드에서 문자 그대로 "|"를 처리하면 안 되나요?

전역 모드에서 문자 그대로 "|"를 처리하면 안 되나요?

내 질문은 다음에서 비롯됩니다.쉘 변수에 정규식을 저장하여 쉘 특정 문자를 인용하는 문제를 피하는 방법은 무엇입니까?.

  1. 오류가 발생하는 이유:

    $ [[ $a = a|b ]]  
    bash: syntax error in conditional expression: unexpected token `|'
    bash: syntax error near `|b'
    

    [[ ... ]]두 번째 피연산자는 내부적으로 =와일드카드 패턴일 것으로 예상됩니다.

    a|b유효한 와일드카드 패턴이 아닙니까 ? 어떤 문법 규칙을 위반하는지 지적할 수 있나요?

  2. 아래의 일부 주석은 |파이프로 해석됨을 나타냅니다.

    그런 다음 =glob 모드를 =~정규식 모드 로 변경하여 |작동하게 합니다.

    $ [[ $a =~ a|b ]]
    

    나는 그것으로부터 배웠다학습 난교p180인치내 이전 게시물|다른 해석 단계(예제의 조건식 구문 분석 포함) 이전에도 해석 시작 시 파이프로 인식됩니다. 그렇다면 |사용될 때 정규식 연산자로 인식되지만 =~잘못 사용될 때는 파이프로 인식되지 않게 하려면 어떻게 해야 합니까 =? 이로 인해 파트 1의 구문 오류가 |파이프로 해석되는 것은 아니라는 생각이 들었습니다 .

    쉘이 표준 입력 또는 스크립트에서 읽는 각 행은 파이프라고 하며 0개 이상의 파이프 문자(|)로 구분된 하나 이상의 명령을 포함합니다. 읽는 각 파이프에 대해 쉘은 이를 명령으로 나누고 파이프의 I/O를 설정한 후 각 명령에 대해 다음을 수행합니다(그림 7-1).

감사해요.

답변1

정당한 이유는 없어

[[ $a = a|b ]]

$a가 문자열인지 테스트하는 대신 오류가 보고되어야 하며 a|bwhile은 [[ $a =~ a|b ]]오류를 반환하지 않습니다.

유일한 이유는 |일반적으로 (외부적으로나 내부적으로 [[ ... ]]) 특수 문자이기 때문입니다. 해당 [[ $a =위치 에는 bash일반 토큰 유형이 필요합니다.단어일반 쉘 명령줄의 인수 또는 리디렉션 대상과 같습니다(그러나 extglobbash 4.1부터 옵션이 활성화된 것처럼).

(통과단어여기요, 내 말은단어다음과 같은 가상의 쉘 구문에서POSIX 사양에 설명된 유형, 쉘은 영어 문자 시퀀스 또는 공백이 아닌 문자 시퀀스와 같은 다른 단어 정의가 아닌 간단한 쉘 명령줄의 토큰으로 이를 구문 분석합니다. foo"bar baz", $(echo x y), 이거 2개야단어에스).

일반 쉘 명령줄에서:

echo a|b

.not a echo a로 파이프됨ba|b단어, 이는 세 개의 마크입니다:a 단어, |토큰 및b 단어토큰.

사용될 때 [[ $a = a|b ]], bash기대하십시오단어( )을 얻었 a으나 예상치 못한 |토큰을 발견하여 오류가 발생합니다.

흥미롭게도 bash불만 사항은 없었습니다.

[[ $a = a||b ]]

이제 a토큰, ||토큰, 또 다른 토큰이 있으므로 b다음과 같은 방식으로 구문 분석됩니다.

[[ $a = a || b ]]

문자열이 $a비어 있는지 테스트합니다.ab

지금:

[[ $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'

(..에서도 사용할 수 있습니다. 특별한 쉘 연산자가 있으므로 yashas로 인용해야 합니다 .)=~zsh=something

bash 3.1은 유사하게 동작했습니다 . 3.2에서는 아마도 ( 첫 번째 쉘 제안에도 불구하고 ) zsh일관성을 유지하기 위해 변경되었지만 여전히 이전 동작을 실행 하거나 되돌릴 수 있습니다( 3.1에서 오류를 반환하는 경우 는 제외). 최신 버전에서 작동합니다) .ksh93bash[[ =~ ]]BASH_COMPAT=31shopt -s compat31[[ $a =~ a|b ]]bashbash -O compat31bash

내가 이 규칙이 혼란스럽다고 말한 이유와 다음을 사용하는 이유가 명확해지기를 바랍니다.

[[ $a =~ $var ]]

다른 쉘을 포함한 이식성에 도움이 됩니다.

답변2

표준 glob("파일 이름 확장자")은 다음과 같습니다. *?. [ ... ]|표준(비extglob) 설정에서 유효한 glob 연산자가 아닙니다.

노력하다:

shopt -s extglob
[[ a = @(a|b) ]] && echo matched

답변3

정규식 일치를 원할 경우 테스트는 다음과 같습니다.

[[ "$a" =~ a|b ]]

관련 정보