문자열이 왼쪽 괄호 인 경우 쉘 브래킷 테스트 오류 대해 확신했다. 그런 다음이를 보았습니다. $ x='(‘ $ [

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

그런 다음이를 보았습니다.

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

같은 오류가 발생하여 문제를 격리하려고합니다.

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

나는 다음과 같은 문제를 해결했다.

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

여전히 여기서 무슨 일이 일어나고 있는지 알아야합니다.



답변

이것은 테스트 [내장이 정의 되는 방식에서 버그를 고려할 수있는 매우 모호한 경우입니다 . 그러나 [많은 시스템에서 사용 가능한 실제 바이너리 의 동작과 일치합니다 . 지금까지 내가 말할 수있는, 그것은 특정의 경우와 일치하는 값을 갖는 변수에 영향을 미치는 [같은 연산자를 (, !, =, -e, 등을.

Bash와 POSIX 쉘에서 그 이유와 그 해결 방법을 설명하겠습니다.


설명:

다음을 고려하세요:

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

문제 없어; 위의 오류는 발생하지 않으며 출력 yes합니다. 이것이 우리가 일을 기대하는 방법입니다. 원하는 '1'경우 비교 문자열 과의 값을 변경할 수 있으며 x예상대로 작동합니다.

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

우리 두 번째 표현을 할 때 버그가 발생합니다 . 유효한 두 번째 표현식은 중요하지 않습니다. 예를 들어

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

outputs yes이며 분명히 유효한 표현식입니다. 하지만 둘을 결합하면

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

Bash x는 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" ]


답변

[일명 test본다 :

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

test괄호 안에 하위 표현식을 허용합니다. 따라서 왼쪽 괄호는 하위 표현식을 열고 구문 분석하려고 시도합니다. 파서는 =하위 표현식에서 첫 번째로 간주 하고 암시 적 문자열 길이 테스트라고 생각하므로 행복합니다. 하위 표현식 뒤에 오른쪽 괄호가 와야하며 대신 구문 분석기가 1대신 찾습니다 ). 그리고 그것은 불평합니다.

test정확히 세 개의 인수를 가지고 있으며, 중간 인수가 인식 된 사업자 중 하나이며, 그것은 괄호 안의 표현식을 찾고없이 1, 3 인자에 해당 연산자를 적용한다.

자세한 내용을 보려면를 man bash검색하십시오 test expr.

결론 :에 의해 사용되는 파싱 알고리즘 test은 복잡합니다. 단순한 표현을 사용하고 사용 연산자 !, &&그리고 ||그들을 결합 할 수 있습니다.


답변