Bash에서 큰따옴표를 일치시키는 방법은 무엇입니까?

Bash에서 큰따옴표를 일치시키는 방법은 무엇입니까?

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

명령 1:

echo "(echo " * ")"

명령 2:

echo "$(echo " * ")"

그들의 출력은

(echo  test.txt ppcg.sh )

그리고

 * 

분명히, 첫 번째 경우에는 *와일드카드가 사용됩니다. 즉, 첫 번째 인용문이 두 번째 인용문과 쌍을 이루고, 세 번째와 네 번째 인용문이 또 다른 쌍을 형성한다는 의미입니다.

두 번째 경우에는 *와일드카드가 없으며 출력에 정확히 두 개의 추가 공백(별표 앞뒤에 하나씩)이 있습니다. 이는 두 번째 따옴표가 세 번째 따옴표와 함께 사용됨을 의미합니다. 첫 번째 따옴표는 다음과 같습니다. 네 번째 따옴표와 함께 사용됩니다.

$()인용문이 다음 인용문과 일치하지 않지만 중첩되는 구조 외에 다른 경우가 있습니까? 이 동작이 잘 문서화되어 있습니까? 그렇다면 해당 문서는 어디서 찾을 수 있나요?

답변1

문자열 내부에 삽입할 수 있는 모든 중첩 구조는 그 안에 추가 문자열을 포함할 수 있습니다. 닫는 태그까지 새 스크립트처럼 구문 분석되며 여러 수준 깊이로 중첩될 수도 있습니다. 그 중 하나만 제외하고 모두 로 시작합니다 $. 이 모든 것은 Bash 매뉴얼과 POSIX 쉘 명령 언어 사양의 조합으로 문서화되어 있습니다.

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

  • 명령은 다음으로 대체됩니다.$( ... ), 당신이 발견한 대로.POSIX는 이 동작을 지정합니다:

    $(command)형식의 경우 왼쪽 대괄호 다음부터 일치하는 오른쪽 대괄호까지 포함하는 모든 문자가 명령을 구성합니다. 유효한 쉘 스크립트는 무엇이든 사용할 수 있습니다.주문하다...

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

  • 또한 명령 대체를 사용하십시오 `.
  • "단어" 요소다음과 같은 고급 매개변수 대체 예${parameter:-word}. 이것"단어"의 정의는 다음과 같다.:

    셸에서 하나의 단위로 처리되는 일련의 문자

    - 여기에는 인용된 텍스트와 심지어 혼합된 인용문도 포함됩니다 a"b"c'd'e. 하지만 확장 프로그램의 실제 동작은 이보다 조금 더 자유롭습니다 ${x:-hello world}.

  • 산술 확장with $(( ... )), 기본적으로는 쓸모가 없지만 명령 대체나 변수 확장을 중첩한 다음 그 안에 유용한 따옴표를 사용할 수도 있습니다.POSIX 상태:

    표현식은 큰따옴표로 묶인 것처럼 처리되어야 하지만 표현식 내의 큰따옴표는 특별히 처리되지 않습니다. 쉘은 매개변수 확장, 명령 대체 및 따옴표 제거를 위해 표현식의 모든 토큰을 확장해야 합니다.

    그래서 이런 행동은 분명히 필요합니다. 이는 echo "abc $((4 "*" 5))"와일드카드가 아닌 산술 연산을 수행한다는 의미입니다.

    이전 스타일의 $[ ... ]산술 확장은 다음과 같습니다.아니요같은 방식으로 처리됩니다. 확장명이 인용되었는지 여부에 관계없이 따옴표가 있으면 오류가 발생합니다. 이 양식에는 더 이상 기록이 없으며 어쨌든 사용할 수 없습니다.

  • 로케일별 번역$"...", 실제로는를 "핵심 요소로 사용합니다. $"하나의 단위로 간주됩니다.

따옴표가 포함되지 않은 중첩의 경우도 있습니다.버팀대 확장: {a,b{c,d},e}"a bc bd e"로 확장됩니다. ${x:-a{b,c}d}하다아니요a{b,c그러나 Nest에서는 " " 뒤에 " " 가 오는 매개변수 대체로 처리됩니다 d}. 저것기록도 있다:

중괄호를 사용할 때 일치하는 닫는 중괄호는 백슬래시로 이스케이프되지 않거나 인용된 문자열 내에 있고 포함된 산술 확장, 명령 대체 또는 인수 확장 내에 있지 않은 첫 번째 "}"입니다.


일반적으로 모든 구분된 구문은 주변 컨텍스트와 독립적으로 해당 본문을 해결합니다.예외는 오류로 처리됩니다.). 본질적으로 $(명령 대체 코드는 파서에게 본문에서 얻을 수 있는 내용을 사용하여 새 프로그램처럼 작동하도록 요청한 다음 하위 파서가 실행될 때 예상되는 종료 토큰(이스케이프되지 않은 )또는 )))이 나타나는지 }확인 합니다. 섭취할 수 있는 것들.

당신이 고려하고 있다면재귀 하강 파서, 이는 기본 사례의 단순한 재귀일 뿐입니다. 문자열 보간을 수행하고 나면 실제로 다른 방법보다 수행하기가 더 쉽습니다. 이러한 구성을 지원하는 셸은 기본 구문 분석 기술에 관계없이 동일한 결과를 제공합니다.

이러한 구조를 통해 임의로 깊은 곳에 참조를 중첩할 수 있으며 예상대로 작동합니다. 중간에 있는 인용문을 보고 혼동하는 사람은 없을 것입니다. 대신에 이는 내부 컨텍스트에서 인용된 새로운 문자열의 시작이 될 것입니다.

답변2

printf아마도 (대신)을 사용하여 이 두 가지 예를 살펴보는 것이 echo도움이 될 것입니다 .

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

(echo (후행 공백을 포함한 첫 번째 단어), 일부 파일 및 끝 단어를 인쇄합니다 ).
대괄호는 단순히 문자열의 일부를 인용합니다 (echo .
별표(두 개의 큰따옴표가 쌍을 이루기 때문에 이제 따옴표가 없음)는 파일 목록과 일치하는 전역 변수로 확장됩니다.
그 다음에는 닫는 괄호가 있습니다.

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

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

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

관련 정보