O problema do echo e do printf está relacionado apenas ao entendimento de que um caractere entre aspas é um "caractere especial".
O mais simples é com uma string em printf '%s' "$string"
.
Neste caso, não há caracteres especiais para processar e tudo o que o comando printf recebe no segundo argumento é impresso como está.
Observe que apenas aspas simples são usadas:
$ printf '%s\n' '\\\\\T ' # nine \
\\\\\T # nine \
Quando a string é usada como o primeiro argumento, alguns caracteres são especiais.
Um par \
representa um único \
e um \T
a único T
:
$ printf '\\\\\T ' # nine \
\\T # four \
Cada um dos quatro pares de \
transformados em um único \
e o último \T
em um T
.
$ printf '\\\\\a ' # nine \
\\ # four \
Cada um dos quatro pares de \
transformados em um único caractere \
e o último \a
em um sino (BEL) (não imprimível).
O mesmo acontece com algumas implementações de eco.
A implementação do traço sempre transforma caracteres especiais de contrabarra.
Se colocarmos esse código em um script:
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
Em seguida, o traço será impresso ( 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 |>
As duas primeiras colunas serão as mesmas (printf) para todos os shells.
Os outros dois serão alterados com a implementação específica do eco usado.
Por exemplo: ash ./script
(busybox ash):
<|\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 | >
Se o caractere usado for um a
, para traço:
<|\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 |\\ | >
E para o bash:
<|\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 | > <|\\ | >
Para isso, nós temos que adicionar a interpretação de que o shell era que os comandos estão sendo executados também podem se aplicar à string de caracteres.
$ printf '%s\n' '\\T '
\\T
$ printf '%s\n' "\\T "
\T
Observe que o shell executa alguma ação na barra invertida entre aspas duplas.
Com este código:
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
Ambos os efeitos são adicionados e obtemos isso:
$ 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 \
Para traços, é ainda mais grave:
$ 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 \