`|`가 문자 그대로 glob 패턴으로 처리되지 않는 이유는 무엇입니까?


13

내 질문은 쉘 변수에 정규 표현식을 저장하면 쉘에 특수 문자를 인용하는 문제어떻게 피합니까? .

  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
bash의 일부 버전에서는 extglob 구문 분석 ( |특별한 위치)이 기본적 으로의 오른쪽에 [[ $var = $pattern ]]있습니다. shopt이 동작이 보이는 버전과 옵션 구성 을 분리하는 것이 흥미로울 것입니다. extglob기본 또는 명시 적 구성이 켜져 있는 경우에만 있습니다.
찰스 더피

2
BTW, 파싱의 이전 단계를 방해하는 파이프 문자를 다소 포괄적으로 배제하고 싶다면 (동의하지는 않지만 독자에게 분명하지는 않습니다.) RHS에서 따옴표를 사용 pattern='a|b'하고 확장 $pattern하십시오.
찰스 더피

@CharlesDuffy, 이것이이 질문에 대한 후속 질문 인 Q & A 에서 이루어진 요점이었습니다 .
Stéphane Chazelas

아-문맥이 의미가 있습니다. 그리고 당신의 대답은 훌륭합니다. 두 가지 모두 감사합니다.
찰스 더피

팀, 아래 답변 중 귀하의 질문에 대한 답변이 있습니까? 그렇다면 수락하는 것을 고려하십시오. 감사합니다!
Jeff Schaller

답변:


13

이유가 없다

[[ $a = a|b ]]

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

유일한 이유는 |일반적으로 (외부 및 내부 [[ ... ]]) 특수 문자 이기 때문입니다 . 이 [[ $a =위치 에서 일반 쉘 명령 행의 인수 또는 경로 재 지정 대상과 같은 bash일반 WORD 인 토큰 유형이 필요 합니다 (단, extglobbash 4.1 이후 옵션이 활성화 된 것처럼 ).

( 여기서 WORD 로, POSIX 사양에 설명 된 것과 같은 가상 쉘 문법 의 단어 를 말합니다. 즉, 쉘은 간단한 쉘 명령 행에서 하나의 토큰으로 구문 분석하고 영어와 같은 단어의 다른 정의는 아닙니다. 문자의 순서 나 간격이없는 문자의 순서. 하나 , 두 등이다 WORD )들.foo"bar baz"$(echo x y)

일반적인 쉘 명령 행에서 :

echo a|b

echo a파이프됩니다 b. a|b하지 않은 것입니다 WORD A : 그것은 세 가지 토큰의 a WORD 하는 |토큰과 b 워드 토큰입니다.

사용할 경우 [[ $a = a|b ]], bash기대 WORD 는 (도착 a),하지만 예기치 않은 발견 한 |오류를 발생시키는 토큰을.

흥미롭게도 다음과 같이 bash불평하지 않습니다.

[[ $a = a||b ]]

이제 a토큰과 ||토큰이 뒤에 b오기 때문에 다음과 같은 방식으로 구문 분석됩니다.

[[ $a = a || b ]]

어떤 그 시험하고 $a있다 a거나하는 것이 b문자열 인 비 웁니다.

지금에:

[[ $a =~ a|b ]]

bash동일한 구문 분석 규칙을 가질 수 없습니다. 동일한 구문 분석 규칙이 있으면 위의 오류가 발생하고 단일 WORD| 인지 확인 하려면 인용해야합니다 . 그러나 bash 3.2부터는 다음을 수행하십시오.a|b

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

그것은 더 이상 a|b정규 표현식 과 일치하지 않지만 정규 표현식 과 일치 합니다 a\|b. 즉, 쉘 인용은 정규 표현식 연산자의 특별한 의미를 제거하는 부작용이 있습니다. 이것은 기능이므로 동작과 유사 [[ $a = "?" ]]하지만 정규 표현식은 그렇지 않지만 와일드 카드 패턴 (에서 사용 [[ $a = pattern ]])은 쉘 단어 (예 : 글로브에서 사용)입니다.

그래서 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. 특수 쉘 연산자 로 =~인용해야 함 ).zsh=something

bash 3.1은 다음과 같이 동작했습니다 zsh. 그것은 아마도과 정렬로, 3.2에서 변경 ksh93(비록 bash첫 해낸 것을 쉘이었다 [[ =~ ]]당신은 여전히 할 수있는)하지만, BASH_COMPAT=31또는 shopt -s compat31그 동안 제외 (이전 동작으로 되돌리려면 [[ $a =~ a|b ]]에서 오류를 반환 bash은 더 이상하지 않습니다, 3.1 에서 bash -O compat31의 새 버전 bash).

내가 왜 규칙이 혼란스럽고 왜 사용했는지 분명히 밝히기를 바랍니다.

[[ $a =~ $var ]]

다른 쉘로의 이식성을 포함합니다.


zsh에서에 오류를보고하고 있습니다 [[ $a = a|b ]].
Isaac

@isaac, 그렇습니다. 그것이 내가 여기서 만드는 요점입니다. 여기서 a|bWORD 가 아니며 a, |b토큰입니다. 마찬가지로이 echo a|b출력되지 않습니다 a|b또는 확장하지 않는 a|b글로브를, 그 인용 할 필요 |는 해당 컨텍스트에서 유효하지 않은 특별한 쉘 캐릭터로. zsh 와일드 카드 연산자 [[ $a = (a|b) ]]처럼 echo (a|b)작동하는 것처럼 (a|b)작동합니다.
Stéphane Chazelas 2016 년

귀하의 답변에 대한 문구와 설명은 bash입니다. 그것은 진실이 아닙니다.
Isaac

11

: 표준 globs와 ( "파일 이름 확장")이다 *, ?하고 [ ... ]. |표준 (비 글로브) 설정에서 유효한 glob 연산자가 아닙니다.

시험:

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

1
감사. 그러나 왜 |문자 그대로 통합 되지 않는가? 구문 오류가 발생하는 이유는 무엇입니까?
Tim

1
인용되지 않았습니다.
Jeff Schaller

3
표준 설정에서 |glob 연산자가 아니므 |로 인용없이 문자 그대로 해석 되지 않습니까? 왜 구문 오류가 있습니까?
Tim

1
|제어 문자입니다. 문자 나 숫자와 같은 방식으로 리터럴 문자로 취급되지 않습니다.
chepner

3
이 모드에서 쉘은 아직 닫히지 않은 [[]] 중간에 파이프 경로 재 지정 문자를 기대하지 않았습니다. [[ $a = a출력이 다른 프로세스로 파이프 될 수있는 유효한 명령이 아닙니다 (적어도 쉘이하려고한다고 생각한 것입니다).
Jason C

5

정규식 일치를 원하면 테스트는 다음과 같습니다.

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

@ 팀 현재 질문을 계속 편집하지 않고 새로운 질문을 열어야합니다.
gardenhead

@gardenhead : 내 업데이트는 질문을 놓칠 경우를 대비하여 변경하는 대신 내 질문을 명확하게하는 것입니다. 내가 추가 한 두 번째 부분 은 내 원래 질문에 대한 하나의 주석 파이프 설명 을 표시하는 것입니다 (구문 오류 이유).
Tim
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.