전체 견적

전체 견적

나는 왜 이 세 명령이 세 가지 다른 답을 주는지 물었습니다.

$ printf "%s\n"   `echo ../.. | sed 's/[.]/\\&/g'`
&&/&&
$ printf "%s\n"  $(echo ../.. | sed 's/[.]/\\&/g')
../.. 
$ printf "%s\n" "$(echo ../.. | sed 's/[.]/\\&/g')"
\.\./\.\.

답변1

이것은 대답하기 어려운 질문입니다. 마지막 설명의 가장 간단한 예입니다.

전체 견적

실제로 완전히 인용된 예는 다음과 같습니다.

$ printf "%s\n"    "$(   echo "../.." | sed 's/[.]/\\&/g'   )"
\.\./\.\.

모든 것이 인용되기 때문에 쉘은 여기서 어떤 트릭이나 변경도 수행하지 않습니다. 가장 안쪽 내용은 echo "../.."인용되므로 파일 이름 확장의 영향을 받지 않습니다. 변경되지 않은 채 sed로 이동하고 sed는 각 점을 로 변경합니다 \&. 그런 다음 명령의 결과도 인용되어 "$(...)"(다시) 쉘에 대한 변경을 방지하고 printf명령도 \.\./\.\.여기에 을 인쇄합니다.

로 변경 ##/##

파일 이름 확장자(와일드카드)가 있으면 ../..어쨌든 ../... 따라서 최종 문자열은 동일합니다. 하지만 이 문제를 테스트해 보겠습니다.

$ echo ../../t*
../../test2.txt ../../tested ../../test.txt

$ set -f     # remove all filename expansion

$ echo ../../t*     ../..
../../t* ../..

*그리고 어떤 경우에도 ?a , a 또는 a 를 포함하지 않는 문자열은 [다음의 영향을 받지 않습니다.패턴 일치 표기법

증명: GLOBIGNORE 설정

$ (GLOBIGNORE='.*:..*'; echo "any" ../../t* ../.. "value")
any ../.. value

globbing(파일 이름 확장)의 영향을 받은 경우 ../..GLOBIGNORE 값으로 인해 제거됩니다.

그러나 파일 이름 확장자가 없는지 확인하기 위해 존재하지 않는 파일 이름으로 전환할 수 있습니다.##/##

따옴표 없이 명령 실행

\따옴표 없이 (명령이 실행되는 경우에도) 쉘이 a 를 제거할 이유가 없습니다 .

$ printf '%s\n' $(printf '%s\n' '\#\#/\#\#')
\#\#/\#\#

사실, 제가 테스트한 쉘 중 어느 것도 두 번째 예에서 보고한 내용을 보여주지 않았습니다. (수정해주세요!)

편집: bash 5.0.17에 버그가 있습니다. 그러나 포인트에서만.

$ b50sh
$ echo $BASH_VERSION
5.0.17(3)-release

$ printf '%s\n' $(printf '%s\n' '\.\./\.\.')
../..

$ printf '%s\n' $(printf '%s\n' '\#\#/\#\#')
\#\#/\#\#

$ printf '%s\n' $(printf '%s\n' '\>\>/\>\>')
\>\>/\>\>

$ exit
$ echo $BASH_VERSION
5.1.4(1)-release

$ printf '%s\n' $(printf '%s\n' '\.\./\.\.')
\.\./\.\.

$ printf '%s\n' $(printf '%s\n' '\#\#/\#\#')
\#\#/\#\#

bash 5.1.4에서 해결된 것 같습니다.

백틱

이것은 가장 어려운 문제입니다. 내부의 모든 백틱은 \\가 됩니다 \.

따라서 sed 명령(sed에 표시된 대로)은 다음과 같습니다 s/[#]/\&/g. 내 생각에 당신이 의미하는 바를 수행하려면 s를 복사해야합니다 \.

$ printf '%s\n'  `printf '%s\n' '##/##' | sed 's/[#]/\\&/g'`
&&/&&

$ printf '%s\n' "`printf '%s\n' '##/##' | sed 's/[#]/\\&/g'`"
&&/&&

$ printf '%s\n' "`printf '%s\n' '##/##' | sed 's/[#]/\\\\&/g'`"
\#\#/\#\#

답변2

Bash 버전 5.0.17에서는 man bash두 가지 명령 대체 형식 사이에 다음과 같은 차이점이 있습니다.

   When  the  old-style  backquote form of substitution is used, backslash
   retains its literal meaning except when followed by $, `,  or  \.   The
   first backquote not preceded by a backslash terminates the command sub‐
   stitution.  When using the $(command) form, all characters between  the
   parentheses make up the command; none are treated specially.

set -x쉘에 있다면 차이점을 볼 수 있습니다:

$ set -x

$ printf "%s\n"   `echo ../.. | sed 's/[.]/\\&/g'`
++ echo ../..
++ sed 's/[.]/\&/g'
+ printf '%s\n' '&&/&&'
&&/&&

디스플레이가 \\&다음과 같이 축소되었습니다 \&.\ \); 는 sed &에서 특별한 의미를 잃어서 , while(새로운 스타일) ..이 되었습니다.&&

$ printf "%s\n"  $(echo ../.. | sed 's/[.]/\\&/g')
++ echo ../..
++ sed 's/[.]/\\&/g'
+ printf '%s\n' ../..
../..

두 백슬래시는 문자 그대로 sed에 전달되며, sed는 이를 ..( 문자 그대로의 백슬래시이며 \.\.특별한 의미를 유지함)로 대체합니다.\\&인용되지 않음그런 다음 결과는 쉘에 의해 반영되고 ../..인용된 명령 대체가 sed 출력을 그대로 인쇄하면 다음을 얻습니다 \.\./\.\..

$ printf "%s\n" "$(echo ../.. | sed 's/[.]/\\&/g')"
++ echo ../..
++ sed 's/[.]/\\&/g'
+ printf '%s\n' '\.\./\.\.'
\.\./\.\.

당신은 또한 볼 수 있습니다...$(...)가 (backtick) 보다 나은 이유는 무엇입니까 ?


Bash 버전 4.4.20에서는 인용되지 않은 버전과 인용된 명령 대체 버전이 $(...)동일한 결과를 제공합니다.

$ echo $BASH_VERSION
4.4.20(1)-release

$ set -x

$ printf "%s\n"  $(echo ../.. | sed 's/[.]/\\&/g')
++ echo ../..
++ sed 's/[.]/\\&/g'
+ printf '%s\n' '\.\./\.\.'
\.\./\.\.

관련 정보