명령 대체 및 큰따옴표: 결과가 다른 이유는 무엇입니까?

명령 대체 및 큰따옴표: 결과가 다른 이유는 무엇입니까?

다음은 백틱과 $()가 어떻게 다르게 동작하는지 보여주는 예입니다.

$ echo "$(echo \"test\")"
"test"
$ echo "`echo \"test\"`"
test

내 이해는 이것이기 때문이라는 것입니다."백틱 안의 백슬래시(\)는 불분명한 방식으로 처리됩니다."

그러나 이것은 다른 이야기인 것 같습니다. 왜냐하면 바깥쪽 큰따옴표를 제거하면 결과가 비슷해지기 때문입니다.

$ echo $(echo \"test\")
"test"
$ echo `echo \"test\"`
"test"

누군가 이것이 어떻게 작동하는지 그리고 왜 "`echo \"test\"`"가 큰따옴표를 제거하는지 설명할 수 있습니까?

답변1

당신 말이 맞아요. 이 경우에는 다른 이야기입니다.

해결책은 아직 남아있습니다같은 링크, 그러나 두 번째 요점은 다음과 같습니다.

  • $() 내부에 중첩된 참조가 훨씬 더 편리합니다.

    [...]

    `...`에는 이식성을 위해 내부 따옴표 주위에 백슬래시가 필요합니다.

그러므로,

echo "`echo \"test\"`"

다음과 같지 않음:

echo "$(echo \"test\")"

하지만 이것은:

echo "$(echo "test")"

이를 다음과 비교해야 합니다.

echo "`echo \\"test\\"`"

답변2

백틱을 사용한 명령 대체가 따옴표를 제거하는 이유는 구현 방식 때문입니다.

  • 백틱 안의 텍스트는 최종 실행 전에 다시 어휘 분석기를 통해 전달됩니다.

    이는 하나의 참조 레벨을 차지하는 어휘 분석기를 통한 첫 번째 전달 결과가 문자열로 유지되고 최종 실행 중에 전체 파서를 다시 통과하기 때문에 발생합니다. 따라서 역따옴표 기반 명령 대체는 두 가지 수준의 인용을 제거합니다.

  • $(...)최종 실행 중에 전체 파서를 통과하기 전에 그 안의 텍스트는 변경되지 않은 상태로 유지됩니다.

    • 이는 ksh로깅을 통해 달성 됩니다.텍스트를 입력하세요')̈́'파서가 일치하는 클로저를 구문 분석하는 부작용으로 $(.

    • 이는 파서가 일치하는 클로저를 구문 분석하고 관련 등가물을 재구성하는 동안 파서가 출력한 이진 구문 트리를 기록함으로써 bosh달성 됩니다.mksh')̈́'$(원래 입력실행된 최종 이진 트리입니다.

    따라서 $(...)명령 기반 대체는 단일 참조 레벨만 제거합니다(이는 일반 명령 실행에서도 발생함).

이 구현으로 인해 백틱 기반 명령 대체는 특히 grep패턴이 해당 명령의 일부인 경우 예기치 않은 동작을 일으킬 수 있습니다. 그렇기 때문에 $(...)먼저 사용하는 것이 좋습니다.

답변3

그 이유는 (이중) 인용 문자열에서 발생하는 일입니다.

쉘 파서는 하나(따옴표 없음)를 찾으면 "다음(따옴표 없음)으로 끝나는 전체 문자열을 "따옴표로 선언합니다. 인용된 문자열 내에서최대백슬래시아니요삭제되었습니다. UN 인용 문자열에서는 백슬래시가 제거됩니다.

~에서POSIX(대부분의 백슬래시 제거):

<backslash>따옴표가 없는 A는 다음 문자의 리터럴 값을 유지해야 합니다.

이는 실제로 표시됩니다(set -x는 구문 분석 후 쉘이 실행하는 것을 보여줍니다).

$ ksh -c 'set -x; echo test\h\jtest; set +x'
+ echo testhjtest
testhjtest

따옴표가 없는 백슬래시는 제거됩니다. 그러나 인용문은 그렇지 않습니다:

$ ksh -c 'set -x; echo "test\h\jtest"; set +x'
+ echo 'test\h\jtest'
test\h\jtest

~에서POSIX 큰따옴표:

<backslash>이스케이프 문자로서의 특별한 의미는 뒤에 다음 문자 중 하나가 오는 경우에만 유지되어야 합니다(이스케이프 문자(백슬래시) 참조).

그렇기 때문에백슬래시는 인용된 문자열에서 제거됩니다.

$   `   "   \   <newline>

예:

$ ksh -c 'set -x; echo "test\"\h\j\"test"; set +x'
+ echo 'test"\h\j"test'
test"\h\j"test

발견된 첫 번째 문자가 (큰)따옴표일 때 이런 일이 발생합니다.

초기 역따옴표( )가 발견 `되면 구문 분석 규칙이 달라집니다 . 첫째, 문자열은 따옴표 없이 시작합니다(내부 큰따옴표는 인용된 부분을 시작할 수 있음).하나범위를 인용하십시오(끝( )까지). `아래 첫 번째 줄의 작은따옴표에 유의하십시오."

$ set -x; echo `echo \"\`echo \\"test\\" \`\"`; set +x
+++ echo '"test"'
++ echo '""test""'
+ echo '""test""'
""test""
+ set +x

$(…)대신 A가 시작됩니다.새로운매번 범위를 참조하십시오.

$ set -x; echo $(echo \"$(echo \\"test\\" )\"); set +x
+++ echo '\test\'
++ echo '"\test\"'
+ echo '"\test\"'
"\test\"
+ set +x

결과는 완전히 다릅니다.

관련 정보