대시의 에코 확장 \\\\이 bash의 에코와 다른 이유는 무엇입니까?

대시의 에코 확장 \\\\이 bash의 에코와 다른 이유는 무엇입니까?

저는 여러 가지 이유로 상당히 이식성이 뛰어난 쉘 스크립트로 작성하려고 하는 작은 오픈 소스 프로젝트를 가지고 있습니다. 자동화된 통합 테스트는 경로 표현식의 적대적인 문자가 올바르게 처리되는지 등을 확인합니다.

/bin/sh공급자가 제공한 사용자를 사용한 bash테스트에서 오류가 발생했습니다 . 이를 다음과 같이 단순화했습니다.

echo "A bug\\'s life"
echo "A bug\\\\'s life"

Bash에서는 다음과 같은 예상 결과가 생성됩니다.

A bug\'s life
A bug\\'s life

내가 개발한 대시를 사용하여 다음을 수행합니다.

A bug\'s life
A bug\'s life

아직 대시에서 버그를 발견하지 못했고 뭔가 빠졌을 수도 있습니다. 이에 대한 합리적인 설명이 있습니까?

답변1

존재하다

echo "A bug\\'s life"

큰따옴표이고 \큰따옴표 내에서 특별하기 때문에 첫 번째 것은 \쉘에서 다음과 같이 이해됩니다.도망가다/인용하다두번째 \. 따라서 A bug\'s life인수가 에 전달됩니다 echo.

echo "A bug\'s life"

똑같은 효과를 얻을 것입니다. '큰따옴표 안에는 특별한 내용이 없으므로 \제거되지 않으므로 전달된 매개변수와 정확히 동일합니다 echo.

설명대로왜 printf가 echo보다 나은가요?echo, 구현 간에는 많은 차이점이 있습니다.

UNIX 호환 구현에서는 dash내장된 echo가 개행 문자, 백스페이스 문자, 8진 문자 시퀀스... 및 백슬래시 자체 에 대한 \이스케이프 시퀀스를 도입하는 데 사용됩니다 .\n\b\0123\\

일부(비 POSIX)에는 -e옵션이 필요하거나 적합성 모드에서만 이 작업을 수행합니다(예: OS/X와 같은 올바른 옵션을 사용하여 빌드할 때 또는 bash환경에서 sh호출할 때 ).SHELLOPTS=xpg_echo

따라서 표준(Unix 표준에만 해당, POSIX는 동작을 지정하지 않음) echo에서

echo '\\'

그것은 다음과 같습니다:

echo "\\\\"

산출하나백슬래시( bash일관성 모드가 아닌 경우):

echo '\\'

출력됩니다백슬래시.

피하고 echo사용하는 것이 가장 좋습니다 printf.

$ printf '%s\n' "A bug\'s life"
A bug\'s life

이 경우 모든 구현에서 동일하게 작동합니다 printf.


dash1은 이와 관련하여 호환되지만 UNIX 사양(POSIX + XSI)에서 요구하는 어떤 것도 출력하지 않습니다 .echoecho -n-n<newline>

답변2

echo 및 printf의 문제는 백틱 문자가 "특수 문자"인 경우를 이해하는 것과만 관련됩니다.

가장 간단한 것은 문자열을 사용하는 것입니다 printf '%s' "$string".
이 경우 처리해야 할 특수 문자가 없으며 두 번째 인수에서 printf 명령이 받는 모든 내용이 그대로 인쇄됩니다.

작은따옴표만 사용된다는 점에 유의하세요.

$ printf '%s\n' '\\\\\\\\\T '       # nine \
\\\\\\\\\T                          # nine \

문자열이 첫 번째 인수로 사용되는 경우 특정 문자는 특수합니다.
\\은 단일 \\T단수를 나타냅니다 T.

$ printf '\\\\\\\\\T '              # nine \
\\\\T                               # four \

네 쌍 각각은 \\단일 로 변환되고 \, 마지막 \T쌍은 단일 로 변환됩니다 T.

$ printf '\\\\\\\\\a '              # nine \
\\\\                                # four \

4개의 쌍 각각은 \\단일 문자로 변환되며 \마지막 문자는 \a벨(BEL) 문자(인쇄할 수 없음)로 변환됩니다.

에서도 같은 상황이 발생합니다일부에코 구현.

대시 구현은 항상 특수 백슬래시 문자를 변환합니다.

이 코드를 스크립트에 넣으면:

set -- '\g ' '\\g ' '\\\g ' '\\\\g ' '\\\\\g ' '\\\\\\g ' '\\\\\\\g ' '\\\\\\\\g ' '\\\\\\\\\g '
for i ; do
    printf '<%-14s> \t<%-9s> \t<%-14s> \t<%-12s>\n' \
       "$(printf '%s ' "|$i|")" \
       "$(printf       "|$i|")" \
           "$(echo         "|$i|")" \
       "$(echo    -e   "|$i|")" ;
done

그런 다음 대시가 인쇄됩니다( dash ./script):

<|\g |         >        <|\g |    >     <|\g |         >        <-e |\g |    >
<|\\g |        >        <|\g |    >     <|\g |         >        <-e |\g |    >
<|\\\g |       >        <|\\g |   >     <|\\g |        >        <-e |\\g |   >
<|\\\\g |      >        <|\\g |   >     <|\\g |        >        <-e |\\g |   >
<|\\\\\g |     >        <|\\\g |  >     <|\\\g |       >        <-e |\\\g |  >
<|\\\\\\g |    >        <|\\\g |  >     <|\\\g |       >        <-e |\\\g |  >
<|\\\\\\\g |   >        <|\\\\g | >     <|\\\\g |      >        <-e |\\\\g | >
<|\\\\\\\\g |  >        <|\\\\g | >     <|\\\\g |      >        <-e |\\\\g | >
<|\\\\\\\\\g | >        <|\\\\\g |>     <|\\\\\g |     >        <-e |\\\\\g |>

처음 두 열은 모든 쉘(printf)에 대해 동일합니다.
나머지 두 개는 사용된 에코의 특정 구현에 따라 달라집니다.

예: ash ./script(Busybox 회색):

<|\g |         >        <|\g |    >     <|\g |         >        <|\g |       >
<|\\g |        >        <|\g |    >     <|\\g |        >        <|\g |       >
<|\\\g |       >        <|\\g |   >     <|\\\g |       >        <|\\g |      >
<|\\\\g |      >        <|\\g |   >     <|\\\\g |      >        <|\\g |      >
<|\\\\\g |     >        <|\\\g |  >     <|\\\\\g |     >        <|\\\g |     >
<|\\\\\\g |    >        <|\\\g |  >     <|\\\\\\g |    >        <|\\\g |     >
<|\\\\\\\g |   >        <|\\\\g | >     <|\\\\\\\g |   >        <|\\\\g |    >
<|\\\\\\\\g |  >        <|\\\\g | >     <|\\\\\\\\g |  >        <|\\\\g |    >
<|\\\\\\\\\g | >        <|\\\\\g |>     <|\\\\\\\\\g | >        <|\\\\\g |   >

사용된 문자가 이면 a대시를 나타냅니다.

<|\a |         >        <| |     >      <| |          >         <-e | |     >
<|\\a |        >        <|\a |    >     <|\a |         >        <-e |\a |    >
<|\\\a |       >        <|\ |    >      <|\ |         >         <-e |\ |    >
<|\\\\a |      >        <|\\a |   >     <|\\a |        >        <-e |\\a |   >
<|\\\\\a |     >        <|\\ |   >      <|\\ |        >         <-e |\\ |   >
<|\\\\\\a |    >        <|\\\a |  >     <|\\\a |       >        <-e |\\\a |  >
<|\\\\\\\a |   >        <|\\\ |  >      <|\\\ |       >         <-e |\\\ |  >
<|\\\\\\\\a |  >        <|\\\\a | >     <|\\\\a |      >        <-e |\\\\a | >
<|\\\\\\\\\a | >        <|\\\\ | >      <|\\\\ |      >         <-e |\\\\ | >

배쉬의 경우:

<|\a |         >        <| |     >      <|\a |         >        <| |        >
<|\\a |        >        <|\a |    >     <|\\a |        >        <|\a |       >
<|\\\a |       >        <|\ |    >      <|\\\a |       >        <|\ |       >
<|\\\\a |      >        <|\\a |   >     <|\\\\a |      >        <|\\a |      >
<|\\\\\a |     >        <|\\ |   >      <|\\\\\a |     >        <|\\ |      >
<|\\\\\\a |    >        <|\\\a |  >     <|\\\\\\a |    >        <|\\\a |     >
<|\\\\\\\a |   >        <|\\\ |  >      <|\\\\\\\a |   >        <|\\\ |     >
<|\\\\\\\\a |  >        <|\\\\a | >     <|\\\\\\\\a |  >        <|\\\\a |    >
<|\\\\\\\\\a | >        <|\\\\ | >      <|\\\\\\\\\a | >        <|\\\\ |    >

이를 위해서는 명령을 실행하는 셸이 문자열에서도 작동할 수 있다는 설명을 추가해야 합니다.

$ printf '%s\n' '\\\\T '
\\\\T
$ printf '%s\n' "\\\\T "
\\T

쉘은 큰따옴표 안에 백슬래시를 사용하여 작업을 수행합니다.

이 코드를 사용하면:

tab='   '
say(){ echo "$(printf '%s' "$a") $tab $(echo "$a") $tab $(echo -e "$a")"; }
a="one \a "         ; say
a="two \\a "        ; say
a="t33 \\\a "       ; say
a="f44 \\\\a "      ; say
a="f55 \\\\\a "     ; say
a="s66 \\\\\\a "    ; say
a="s77 \\\\\\\a "   ; say
a="e88 \\\\\\\\a "  ; say
a="n99 \\\\\\\\\a " ; say

두 가지 효과가 모두 추가되어 다음과 같은 결과를 얻습니다.

$ bash ./script
one \a           one \a          one  
two \a           two \a          two  
t33 \\a          t33 \\a         t33 \a 
f44 \\a          f44 \\a         f44 \a 
f55 \\\a         f55 \\\a        f55 \ 
s66 \\\a         s66 \\\a        s66 \ 
s77 \\\\a        s77 \\\\a       s77 \\a 
e88 \\\\a        e88 \\\\a       e88 \\a 
n99 \\\\\a       n99 \\\\\a      n99 \\ 

대시의 경우 상황은 더욱 심각합니다.

$ dash ./script
one              one             -e one  
two              two             -e two  
t33 \a           t33             -e t33  
f44 \a           f44             -e f44  
f55 \            f55 \           -e f55 \ 
s66 \            s66 \           -e s66 \ 
s77 \\a          s77 \a          -e s77 \a 
e88 \\a          e88 \a          -e e88 \a 
n99 \\           n99 \           -e n99 \ 

관련 정보