bash의 큰 따옴표는 어떻게 일치합니까?


15

사용하고 GNU bash 4.3.48있습니다. 단일 달러 기호 만 다른 다음 두 명령을 고려하십시오.

명령 1 :

echo "(echo " * ")"

명령 2 :

echo "$(echo " * ")"

그들의 출력은 각각

(echo  test.txt ppcg.sh )

 * 

그래서 당연히 제 경우에는 *제 인용 부호가 다른 한 쌍의 쌍을 형성하는 두 번째, 세 번째 및 네 번째 형태로 진행하는 것이 수단 globbed된다.

두 번째 경우에는을 *붙 잡지 않고 출력에 두 개의 추가 공간이 있습니다. 하나는 별표 앞과 뒤에 있습니다. 두 번째 인용 부호는 세 번째 인용 부호와 함께 가고 첫 번째는 네 번째 부호와 함께 있음을 의미합니다.

$()따옴표가 다음 따옴표와 일치하지 않고 대신 중첩 되는 구성 외에 다른 경우 가 있습니까? 이 동작은 잘 문서화되어 있으며, 그렇다면 해당 문서를 어디에서 찾을 수 있습니까?



다시 한 번, UL SE의 구문 강조는 잘못된 것이며 잘못된 것입니다.
Weijun Zhou

답변:


14

문자열 내부에 삽입 될 수있는 중첩 구조는 내부에 추가 문자열을 가질 수 있습니다. 새 스크립트처럼 파싱 마커까지 구문 분석되며 여러 수준으로 중첩 될 수도 있습니다. 그중 하나는 모두로 시작합니다 $. 이들 모두는 Bash 매뉴얼과 POSIX 쉘 명령 언어 사양의 조합으로 문서화되어 있습니다.

이러한 구조에는 몇 가지 경우가 있습니다.

  • $( ... )찾은으로 명령 대체 . POSIX는이 동작을 지정합니다 .

    $(command)형식을 사용하면 여는 괄호 다음에 일치하는 닫는 괄호 뒤에있는 모든 문자가 명령을 구성합니다. 유효한 쉘 스크립트는 명령에 사용할 수 있습니다 ...

    따옴표는 유효한 쉘 스크립트의 일부이므로 일반적인 의미로 허용됩니다.

  • 을 사용한 명령 대체 `도.
  • 의 "단어"요소 와 같은 고급 매개 변수 치환 인스턴스${parameter:-word} . "word"정의는 다음과 같습니다.

    쉘에서 단위로 취급되는 일련의 문자

    -인용 된 텍스트와 따옴표가 혼합되어 있습니다 a"b"c'd'e-확장의 실제 동작은 그보다 약간 자유 롭고 예를 들어 ${x:-hello world}작동합니다.

  • 산술 확장 과 함께 $(( ... )), 그것은 거의 쓸모가 있지만 거기에 (하지만 당신은 둥지 명령 치환이나 변수 확장이 너무하고 그 내부에 유용하게 따옴표를 할 수 있습니다). POSIX는 다음과 같이 말합니다 .

    표현은 큰 따옴표가 특수하게 처리되지 않는 것을 제외하고는 큰 따옴표로 표현 된 것처럼 취급됩니다. 쉘은 매개 변수 확장, 명령 대체 및 따옴표 제거를위한 표현식에서 모든 토큰을 확장해야합니다.

    따라서이 동작은 명시 적으로 필요합니다. 그것은 글 echo "abc $((4 "*" 5))"로빙이 아니라 산술을 의미 합니다.

    그 이전 스타일하지만 참고 $[ ... ]산술 확장되어 있지 같은 방식으로 처리 : 나타나는 경우 따옴표에 관계없이 확장이 인용되는 경우의 여부, 오류가 될 것입니다. 이 양식은 더 이상 문서화되지 않으며 어쨌든 사용되지 않습니다.

  • 로 로케일 별 번역.$"..." 실제로 "핵심 요소로 사용합니다 . $"단일 단위로 취급됩니다.

괄호 확장 과 함께 따옴표를 포함하지 않고 예상치 못한 중첩 사례가 하나 더 있습니다 . {a,b{c,d},e}"a bbc e"로 확장됩니다. 그러나 중첩 ${x:-a{b,c}d}되지 않습니다 . " a{b,c"다음에 " d}"를 제공하는 매개 변수 대체로 처리됩니다 . 그것은 또한 문서화되어 있습니다 :

중괄호를 사용하는 경우 일치하는 끝 중괄호는 백 슬래시 또는 따옴표로 묶인 문자열 내에서 이스케이프되지 않고 내장 된 산술 확장, 명령 대체 또는 매개 변수 확장 내에서 첫 번째 '}'입니다.


일반적으로 모든 구분 된 구문은 주변 컨텍스트와 독립적으로 본문을 구문 분석합니다 ( 예외는 버그로 처리됨 ). 본질적으로 $(명령 대체 코드를 보면 파서가 새로운 프로그램 인 것처럼 본문에서 가능한 것을 소비하도록 요청한 다음 하위 파서가 실행되면 예상 종료 마커 (이스케이프되지 않은 )또는 ))또는 })가 나타나는지 확인합니다. 소비 할 수있는 것 중에서

재귀 하강 파서 의 기능에 대해 생각 하면 기본 사례에 대한 간단한 재귀입니다. 문자열 보간법을 얻은 후에는 실제로 다른 방법보다 쉽습니다. 기본 구문 분석 기술에 관계없이 이러한 구성을 지원하는 쉘은 동일한 결과를 제공합니다.

이러한 구성을 통해 원하는만큼 따옴표를 중첩시킬 수 있으며 예상대로 작동합니다. 중간에 따옴표를 보면 혼동되지 않습니다. 대신, 그것은 내부 맥락에서 인용 된 새로운 문자열의 시작이 될 것입니다.


감사. 에서 "blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")", 왜 두 번째 큰 따옴표 없습니다 (회신에서 구문 강조 같이) 첫 번째 따옴표의 끝,하지만 문자열 내부의 시작은 $(...)? bash 파서가 상향식이 아닌 하향식이기 때문입니까?
모든

2
처리에는 많은 변형이 있으며 "${var-"foo"}"( 예를 들어 Bourne 또는 Korn 쉘 echo "${-+"*"}"과 동일 echo *) 다음 버전의 표준에서는 동작이 명확하게 지정되지 않습니다. mail-archive.com/austin-group-l@opengroup.org/msg00167.html의
Stéphane Chazelas

3

아마도 printf(대신 대신 echo) 두 예제를 보면 도움이 될 것입니다.

$ printf '<%s> ' "(echo " * ")"; echo
<(echo > <test.txt> <ppcg.sh> <file1> <file2> <file3> <)>

그것은 인쇄 (echo (후행 공간을 포함하는 첫 번째 단어), 일부 파일 및 닫는 단어를 ).
괄호는 인용 된 문자열의 일부일뿐입니다 (echo .
별표 (지금은 두 개의 큰 따옴표가 쌍을 이루므로 인용 부호가 없음)가 일치하는 파일 목록에 대한 글로 확장됩니다.
그리고 닫는 괄호.

그러나 두 번째 명령은 다음과 같이 작동합니다.

$ printf '<%s> ' "$(echo " * ")" ; echo
< * >

$명령 대체를 시작합니다. 인용을 새로 시작합니다.
별표는 따옴표로 묶여 " * "있으며 명령 (여기서는 따옴표로 묶인 문자열이 아님)이 echo출력하는 것입니다. 마지막으로를 printf다시 포맷하고 *로 인쇄합니다 < * >.

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