존재하다HEREDOC 텍스트를 쉘 스크립트 변수에 어떻게 넣나요?누군가가 다음을 사용하여 문제를 보고합니다.여기 문서내부에 따옴표 구분 기호가 있습니다.$(...)
명령 대체\
, 문서 줄 끝에 있는 백슬래시가 트리거됩니다.Newline - 줄 계속 연결, 여기에 있는 문서는 동일하지만외부명령 대체가 예상대로 작동합니다.
다음은 단순화된 예제 문서입니다.
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
여기에는 줄 끝에 백틱과 백슬래시가 포함됩니다. 구분 기호가 인용되어 있으므로 본문 내에서 확장이 발생하지 않습니다. Bourne과 같은 모든 프로그램에서는 그대로 출력되는 것을 볼 수 있습니다. 동일한 문서를 다음과 같은 명령 대체에 넣으면:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
그러면 더 이상 동일하게 동작하지 않습니다.
dash
,ash
,zsh
,ksh93
, BusyBoxash
및mksh
SunOS 5.10 POSIX는sh
모두 이전과 마찬가지로 문서의 내용을 그대로 제공합니다.- Bash 3.2에서는 백틱 불일치로 인해 구문 오류가 발생합니다. 일치하는 백틱을 사용하면 콘텐츠를 명령으로 실행하려고 시도합니다.
- Bash 4.3에서는 "ghi"와 "jkl"을 오류 없이 한 줄로 축소합니다. 이것
--posix
옵션이에 영향을 미치지 않습니다. 선행은 이루기가 어렵다pdksh
같은 방식으로 작동한다고 말해 주세요(감사합니다!).
원래 질문에서 나는 이것이 Bash 파서의 버그라고 말했습니다. 응? [고쳐 쓰다:예] 내가 찾을 수 있는 POSIX의 관련 텍스트(모두 Shell 명령 언어 정의에서)는 다음과 같습니다.
- §2.6.3 명령 대체:
$(command) 형식의 경우 왼쪽 대괄호 다음부터 오른쪽 대괄호까지 포함하는 모든 문자가 명령을 구성합니다. 유효한 쉘 스크립트는 무엇이든 사용할 수 있습니다.주문하다, 지정되지 않은 결과를 생성하는 리디렉션만으로 구성된 스크립트는 제외됩니다.
- §2.7.4 여기 문서:
만약 어떤 부분이라도단어인용된 경우 인용 제거를 수행하여 구분 기호를 형성해야 합니다.단어, 문서 줄은 여기에서 확장되어서는 안 됩니다.
- §2.2.1 이스케이프 문자(백슬래시):
<newline>이 <backslash> 뒤에 오면 쉘은 이를 줄 연속으로 해석합니다. 입력을 토큰으로 분할하기 전에 <backslash> 및 <newline>을 제거해야 합니다.
- §2.3 토큰 식별:
언제io_여기토큰이 문법에 의해 인식되었습니다(참조:쉘 구문), 다음 줄 바로 다음에 나오는 하나 이상의 줄새로운 팀토큰은 여기에서 하나 이상의 문서 본문을 형성하며 다음 규칙에 따라 구문 분석되어야 합니다.여기 문서.
처리하지 못할 때io_여기, 쉘은 아래의 첫 번째 적용 가능한 규칙을 입력의 다음 문자에 적용하여 입력을 토큰으로 나누어야 합니다. ...
...
- 현재 문자가 <백슬래시>, 작은따옴표 또는 큰따옴표이고 따옴표가 없으면 인용된 텍스트가 끝날 때까지 후속 문자의 인용에 영향을 줍니다. 인용규칙은 다음과 같습니다인용하다. 토큰 인식 중에는 대체가 실제로 수행되어서는 안 되며, 결과 토큰에는 입력에 나타난 문자(<newline> 연결 제외)가 수정되지 않고 정확히 포함되어야 하며, 따옴표와 끝 사이에 삽입되거나 묶인 따옴표 또는 인용된 텍스트도 포함되어야 합니다. 교체 연산자.
이에 대한 나의 해석은 $(
종료까지의 모든 문자가 )
문자 그대로 쉘 스크립트를 구성한다는 것입니다. 따라서 문서 처리는 일반적인 토큰화 대신 여기에서 발생하며, 이는 해당 문서의 내용이 따옴표로 묶인 구분 문자를 갖는다는 것을 의미합니다. 그대로 처리되며 이스케이프 문자는 절대 나타나지 않습니다. 하지만 이 상황은 전혀 해결되지 않고, 두 가지 행위 모두 허용된다는 주장이 보입니다. 어딘가에서 관련 텍스트를 건너뛰었을 수도 있습니다.
- 이 상황이 다른 곳에서 더 명확하게 밝혀졌나요?
- 이식 가능한 스크립트는 (이론적으로) 무엇에 의존할 수 있어야 합니까?
- 표준에서는 이러한 쉘(Bash 3.2/Bash 4.3/기타 모든 것)의 특정 처리를 요구합니까? 금지? 허용됩니까?
답변1
이것은 Bash 메일링 리스트에서 요청되었으며,관리자는 이것이 버그라고 확인했습니다.
또한 POSIX의 텍스트가 "반드시 모호한 것은 아니지만 주의 깊게 읽어야 한다"고 언급해 이에 대한 명확한 설명을 요청했습니다.그들의 답변에는 문제에 대한 설명과 기준에 대한 설명이 포함되었습니다.다음과 같이:
명령 대체는 잘못된 점을 지적한다는 점에서만 관련이 있습니다.
여기서는 문서의 구분 기호가 인용되어 있으므로 줄이 확장되지 않습니다. 이 경우 쉘은 마치 인용된 것처럼 입력에서 행을 읽습니다. 백슬래시가 인용된 컨텍스트에 나타나면 이스케이프 문자로 작동하지 않으며(아래 참조) 백슬래시 줄 바꿈에 대한 특별한 처리가 발생하지 않습니다. 실제로 구분 기호의 일부가 인용되면 여기의 문서 줄은 작은따옴표로 읽혀집니다.
Posix 2.2.1의 텍스트는 이상하게 작성되었지만 이는 백슬래시가 인용되지 않은 경우에만 특별히 처리된다는 것을 의미합니다. 백슬래시를 인용하고 작은따옴표만 사용하거나 다른 백슬래시를 사용하여 모든 확장을 억제할 수 있습니다.
해당 부분은 작은따옴표를 의미하는 "확장되지 않은" 텍스트임을 주의 깊게 읽어보세요. 표준은 2.2에서 이 문서가 "인용의 또 다른 형태"라고 말하지만, 단어가 전혀 확장되지 않는 유일한 인용 형태는 작은 따옴표입니다. 따라서 작은따옴표와 완전히 동일하지만 다른 인용 형태입니다.