다음은 백틱과 $()가 어떻게 다르게 동작하는지 보여주는 예입니다.
$ 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 인용 문자열에서는 백슬래시가 제거됩니다.
<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
결과는 완전히 다릅니다.