![Bash에서 큰따옴표를 일치시키는 방법은 무엇입니까?](https://linux55.com/image/126973/Bash%EC%97%90%EC%84%9C%20%ED%81%B0%EB%94%B0%EC%98%B4%ED%91%9C%EB%A5%BC%20%EC%9D%BC%EC%B9%98%EC%8B%9C%ED%82%A4%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
을 사용하고 있습니다 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
다시 포맷 *
하고 < * >
.