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


27

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

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

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

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

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

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

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

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


2
해결 방법으로 bash에서 다음을 사용할 수 있습니다.[[ "$x" = '1' && "$y" = '1' ]]
terdon

3
테스트를위한 POSIX 사양은 이러한 이유로 명시 적으로 설명 -a되어 -o있으며 더 이상 사용되지 않습니다 ( [OB]사양 옆 의 위 첨자 의미). 당신이 [ "$x" = 1 ] && [ "$y" = 1 ]대신 쓴다면, 당신은 괜찮을 것이고, 잘 정의되고 표준화 된 행동의 영역 안에있을 것입니다.
Charles Duffy

6
이것이 사람들이 [ "x$x" = "x1" ]인수가 연산자로 잘못 해석되는 것을 막기 위해 사용했던 이유 입니다.
Jonathan Leffler

@JonathanLeffler : 이봐 요, 당신은 내 대답을 공평하지 않은 한 문장으로 요약했습니다! :) dashBash가 아닌 POSIX 셸을 사용하는 경우 여전히 유용한 방법입니다.
명목 동물

나는 내 질문에 대답하기 위해 시간을내어 주셔서 감사합니다. 정말로 감사합니다. :)! 또한 내 질문에 대한 중요한 편집에 감사드립니다. 이 포럼에 들어가면 알카트라즈에서 탈출하는 것과 같은 스릴을 느낄 수 있습니다. 잘못된 움직임은 당신의 삶을 의미합니다. 어쨌든 나는이 의견이 삭제되기 전에 내 감사가 당신에게 도달하기를 정말로 바랍니다.
Claudio

답변:


25

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

1
[내장 버그 의 동작을 호출하지 않습니다 . 무엇이든, 그것은 본질적인 디자인 결함입니다. [[은 내장 키워드 가 아닌 쉘 키워드 이므로 따옴표 제거 전에 물건을보고 실제로 일반적인 단어 분리를 무시합니다. 예를 들어 문맥이 정상과 다르기 때문에 [[ $x == 1 ]]를 사용할 필요가 없습니다 . 어쨌든 이것은 의 함정을 피할 수있는 방법 입니다 . POSIX는 작동 방식을 따라야하며 bash는 없이도 대부분 POSIX를 준수 하므로 키워드로 변경 하는 것은 매력적이지 않습니다. "$x"[[[[[[--posix[
Peter Cordes

POSIX에서는 해결 방법을 권장하지 않습니다. 에 두 번의 호출을 사용하십시오 [.
와일드 카드

@PeterCordes : 그렇습니다. 좋은 지적. (아마도 첫 번째 단락에서 정의 된 대신 디자인을 사용해야 했지만 POSIX 이전의 역사로 인해 행동에 부담이 되었으므로 대신 후자를 선택했습니다.) 필자는 예제 스크립트에서 개인적으로 사용 하는 것을 피 합니다. 항상 추천하는 인용 제안에 대한 예외 (따옴표를 생략하는 것이 내가 볼 수있는 스크립트 버그의 가장 일반적인 이유이므로) 인용 제안을하지 않고 규칙에 예외가있는 이유를 설명하는 간단한 단락을 생각하지 않았습니다. 용의자. [[[[[
공칭 동물

@Wildcard : 아니요. POSIX는 이 방법을 권장 하지 않으며 , 이것이 중요합니다. 권한이이 관행을 권장하지 않기 때문에 이것을 나쁘게 만들지 않습니다. 실제로, 내가 지적했듯이, 이것은 shPOSIX 표준화에 앞서서 스크립트에 사용 된 역사적 관행 입니다. 괄호 표현식 및 사용 -a-o테스트 논리 연산자 / [더 효율적임을 (비아 식 체인에 의존 &&하고 ||); 단지 현재 기계에서는 그 차이가 중요하지 않습니다.
명목 동물

@Wildcard : 그러나 개인적으로 &&and를 사용하여 테스트 식을 연결하는 것을 선호 ||하지만 그 이유는 인간이 버그를 도입하지 않고 유지 관리 (필요한 경우 / 읽기, 이해 및 수정 가능)하기 쉽기 때문입니다. 그래서 나는 당신의 제안을 비판하는 것이 아니라 제안 뒤에있는 추론 만합니다. (매우 비슷한 이유로,의 경우는 .LT., .GE., FORTRAN 77 등 비교 연산자 훨씬 더 인간 친화적 인 버전을 가지고 <, >=이후 버전에서 등.)
공칭 동물

11

[일명 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은 복잡합니다. 단순한 표현을 사용하고 사용 연산자 !, &&그리고 ||그들을 결합 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.