나는 문자열을 인용하는 것이 쉘이 구문 분석하는 것을 피하기 위해 항상 좋은 습관이라는 사실에 대해 확신했다.
그런 다음이를 보았습니다.
$ 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
은 복잡합니다. 단순한 표현을 사용하고 사용 쉘 연산자 !
, &&
그리고 ||
그들을 결합 할 수 있습니다.