나는 문자열을 인용하는 것이 문자열을 구문 분석하는 쉘을 피하기 위해 항상 좋은 습관이라고 확신했습니다.
그러다가 나는 이것을 발견했습니다 :
$ 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
x
Bash는 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
상대적으로 복잡합니다. 그냥 간단한 표현을 사용하고껍데기연산자를 사용 !
하여 &&
결합합니다 ||
.