문자열이 왼쪽 대괄호인 경우 쉘 브래킷 테스트 오류

문자열이 왼쪽 대괄호인 경우 쉘 브래킷 테스트 오류

나는 문자열을 인용하는 것이 문자열을 구문 분석하는 쉘을 피하기 위해 항상 좋은 습관이라고 확신했습니다.

그러다가 나는 이것을 발견했습니다 :

$ x='('
$ [ "$x" = '1' -a "$y" = '1' ]
bash: [: `)' expected, found 1

문제를 분리하려고 시도했지만 동일한 오류가 발생했습니다.

$ [ '(' = '1' -a '1' = '1' ]
bash: [: `)' expected, found 1

나는 다음과 같이 문제를 해결했습니다.

[ "$x" = '1' ] && [ "$y" = '1' ]

난 아직도 여기서 무슨 일이 일어나고 있는지 알아야 해요.

답변1

[이는 매우 모호한 경우이며 테스트 내장이 정의되는 방식에 버그가 있다고 생각할 수도 있지만 이는 [많은 시스템에서 사용할 수 있는 실제 바이너리의 동작과 일치합니다. 제가 아는 한 , , , 등의 [연산자와 일치하는 값을 가진 특정 케이스와 변수 에만 영향을 미칩니다.(!=-e

Bash 및 POSIX 셸에서 이 문제를 해결하는 이유와 해결 방법을 설명하겠습니다.


설명하다:

다음을 고려하세요:

x="("
[ "$x" = "(" ] && echo yes || echo no

문제 없습니다. 위의 코드는 오류나 출력을 생성하지 않습니다 yes. 이것이 우리가 기대하는 작동 방식입니다. 원하는 경우 비교 문자열을 '1'및 값 으로 변경할 수 x있으며 예상대로 작동합니다.

실제 /usr/bin/[바이너리도 같은 방식으로 동작합니다. 예를 들어 실행하면 '/usr/bin/[' '(' = '(' ']'프로그램에서 인수가 단일 문자열 비교 작업으로 구성되어 있음을 감지할 수 있으므로 오류가 발생하지 않습니다.

언제 우리가그리고두 번째 표현을 사용하세요. 유효한 한 두 번째 표현이 무엇인지는 중요하지 않습니다. 예를 들어,

[ '1' = '1' ] && echo yes || echo no

output yes은 분명히 유효한 표현이지만, 두 가지를 결합하면

[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no

xBash는 is 또는 인 경우에만 (표현식을 거부합니다 !.

실제 프로그램을 사용하여 위의 내용을 실행하면 [, 즉

'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no

오류는 이해할 수 있습니다. 쉘이 변수 대체를 수행하기 때문에 /usr/bin/[바이너리는 인수 ( = ( -a 1 = 1와 종결자만 수신하므로 ]여는 괄호가 하위 표현식을 시작하는지 여부를 당연히 구문 분석할 수 없습니다.그리고 운영이 포함됩니다. 물론 이를 두 개의 문자열 비교로 구문 분석하는 것이 가능하지만 그렇게 하면 괄호로 묶인 하위 표현식이 있는 올바른 표현식에 적용될 때 문제가 발생할 수 있습니다.

실제로 문제는 쉘 내장이 표현식을 확인하기 전에 값을 확장한 [것처럼 동작한다는 것이다.x

(이러한 모호함과 변수 확장과 관련된 기타 사항은 [[ ... ]]Bash가 테스트 표현식을 구현하고 이제 테스트 표현식 사용을 권장하는 중요한 이유입니다.)


해결 방법은 간단하며 sh이전 쉘을 사용하는 스크립트에 자주 나타납니다. 일반적 x으로 표현식이 문자열 비교로 인식되도록 하기 위해 문자열(비교되는 두 값) 앞에 "안전한" 문자를 추가합니다.

[ "x$x" = "x(" -a "x$y" = "x1" ]

답변2

[일명 test참조:

 argc: 1 2 3 4  5 6 7 8
 argv: ( = 1 -a 1 = 1 ]

test괄호 안의 하위 표현식을 허용하므로 왼쪽 괄호가 하위 표현식을 열고 이를 구문 분석하려고 시도합니다. 파서는 이를 =하위 표현식의 첫 번째 것으로 간주하고 이를 암시적 문자열 길이 테스트로 간주합니다. 따라서 하위 표현식을 따라야 합니다. 파서가 1대신 찾을 닫는 괄호로 ).

정확히 세 개의 인수가 있고 test가운데 인수가 인식된 연산자 중 하나인 경우 괄호 안의 하위 표현식을 찾지 않고 첫 번째 및 세 번째 인수에 해당 연산자를 적용합니다.

자세한 내용을 보려면 를 확인하고 man bash검색 하세요 test expr.

결론: 사용된 구문 분석 알고리즘은 test상대적으로 복잡합니다. 그냥 간단한 표현을 사용하고껍데기연산자를 사용 !하여 &&결합합니다 ||.

관련 정보