Qual é o inverso de echo -e?

13

Se eu tiver uma sequência com caracteres não imprimíveis, novas linhas ou tabulações, existe uma maneira echode imprimir essa sequência e mostrar códigos para esses caracteres (por exemplo, \npara nova linha, \bpara backspace)?

drs
fonte
2
você pode usar o comando printf, ver o homem printf
Golfo Pérsico
12
e- ohce* rimshot *
David Richerby
3
printf '%q' "$str"imprimirá a string escapada. Não estou adicionando isso como resposta, já que não é a mesma forma de escape que echo -eusa - em vez disso, destina-se a ser segura para avaliação - mas (1) é boa o suficiente se seu objetivo é a legibilidade humana, (2) é bom o suficiente se seu objetivo for a geração segura de shell e (3) echo -efor mal e errado de qualquer maneira (se você ler as especificações do POSIX, verá que printf é a maneira preferida de formatar a sequência de caracteres e echo -enão é garantido pelo POSIX da linha de base em todos).
Charles Duffy

Respostas:

7

Existem várias maneiras de fazer isso. Os dois mais portáteis que eu conheço são sede od- ambos são POSIX.

printf '\n\r\b\t\033[01;31m' | sed -n l

Gosta de ... readestilo escapa - estilo C.

RESULTADO

$
\r\b\t\033[01;31m$

od é um pouco mais configurável ...

printf '\n\r\b\t\033[01;31m' |
od -v -w12 -t c -t a -A n

 \n  \r  \b  \t 033   [   0   1   ;   3   1   m
 nl  cr  bs  ht esc   [   0   1   ;   3   1   m

Se você quiser saber em que todas essas opções você pode procurar man od, mas especifiquei que quero dois tipos de escapes - a -t cbarra invertida e os -t acaracteres nomeados. A -wopção usada acima não é especificada pelo POSIX.

E aqui está uma pequena função de shell que imprimirá de maneira portável os valores octais de cada byte em seus argumentos - os quais, é claro, odpodem lidar também com -t o:

proctal() (LC_ALL=C
    for a do while [ -n "$a" ] 
    do printf %o\\n "'$a"
    a=${a#?}; done; done)  

Essa é simples. Isso é um pouco mais complicado. printf -qPorém, ele deve poder fazer o que as implementações específicas do shell podem fazer.

bsq() (set -f; export LC_ALL=C IFS=\'
    for a do q=${a##*\'}; printf \'
    [ -n "${a#"$q"}" ] &&
        printf "%s'\''" ${a%\'*}
    printf "%s'\n'''''\n" "$q"; done |
    sed -n "/'''''"'/!H;1h;//!d;$!n;x;l' |
    sed -e :n -e '/\\$/N;s/.\n//;tn
        s/\([^\\]\\\(\\\\\)*\)\([0-9]\)/\10\3/g
        s/\\\\'"''/\\\\''"'/g;s/$$//'
)

Usando a sequência de exemplo anterior com um pouco mais:

bsq "$(printf '\n\r\'\''b\t\033[01;31m')"

RESULTADO

'\n\r\\'\''b\t\0033[01;31m'

É apenas um pouco diferente. Você pode notar que há 0um \backslash extra e um extra . Isso permite uma tradução fácil para um readou um %b printfargumento. Por exemplo:

i=0
until [ $((i=$i+1)) -gt 5 ]
do touch "\%$i$(printf 'hey\b \t;\n\033 ')"
done   #just for ugly's sake

bsq * | eval "
    printf '<%b>\n' $(tr \\n \ )
" | tee /dev/fd/2 |
sed -n l

RESULTADO

<\%1he  ;
>
<\%2he  ;
>
<\%3he  ;
>
<\%4he  ;
>
<\%5he  ;
>
<\\%1hey\b \t;$
\033 >$
<\\%2hey\b \t;$
\033 >$
<\\%3hey\b \t;$
\033 >$
<\\%4hey\b \t;$
\033 >$
<\\%5hey\b \t;$
\033 >$
mikeserv
fonte
@ StéphaneChazelas Vai ainda só fazem caracteres de byte único, mas espero que a sua menos propensos a estragar agora.
mikeserv
1
Deixe-me levá-lo à marca 10k :)
Ramesh
Woohoo !!!!!!!!!
slm
@ slm - deixe-me adivinhar .. Você realmente gostou do proctal?
mikeserv
@ StéphaneChazelas - você tem alguma opinião bsq()- está faltando alguma coisa? Eu pergunto porque não estou totalmente confiante sobre as barras invertidas.
mikeserv
12

Quando você remove a -eopção para echo, in bashe desde que a xpg_echoopção não tenha sido ativada, ela deve imprimir as seqüências como nada mais que o texto original. Então, \ne \tapareceria literalmente isso.

Exemplo

$ echo "hi\t\tbye\n\n"
hi\t\tbye\n\n

$ echo -e "hi\t\tbye\n\n"
hi      bye

Você também pode usar o printfcomando interno de ksh93, zshou bashpara finagle isso também.

$ printf "%q\n" "$(echo -e "hi\t\tbye\n\nbye")"
$'hi\t\tbye\n\nbye'

( bashsaída mostrada acima. Existem algumas variações dependendo do shell).

trecho dehelp printf embash

%q cite o argumento de uma maneira que possa ser reutilizada como entrada do shell

slm
fonte
1
Não é isso printf %qque trunca os \ns finais , é a $()captura de saída que os tira.
ecatmur 9/09/14
@ catmur - obrigado, escrevi isso tarde da noite e não tentei depurar ainda mais. Você estaria correto, é o subshell que os tira. Aqui está um motivo: unix.stackexchange.com/questions/17747/…
slm
... de qualquer maneira, rodar printfdentro de um subshell para capturar sua saída é bobo, pois printf -v varnamecolocará a saída diretamente em uma variável, sem subshell envolvido.
Charles Duffy
@CharlesDuffy - não estou seguindo você, não estou executando printfem um subshell, estava echoem um, puramente para demonstrar que você pode pegar a saída de caractere especial echoe convertê-la novamente na notação de escape.
Slm
@ slm, essa foi uma resposta ao primeiro comentário (bem, o código ao qual o primeiro comentário respondeu), não o código como o encontrei agora. Se deduzi algo impreciso sobre o estado de edição anterior, minhas desculpas.
Charles Duffy
5

Você poderia usar algo como,

$ cat filename
Ramesh is testing
New Line        is

Agora, você pode fazer algo como,

$ cat -A filename

Resultado

Ramesh is testing$
New Line ^Iis $

Outro teste geral sem nenhum arquivo é como,

$ echo Hello$'\t'world. | cat -A

O comando acima produz a saída como,

Hello^Iworld.$

Referências

Ramesh
fonte
4
Ou, em não-GNU implementações de gato, por exemplo MacOS / X, leve seu gato ao veterinário ... -vet gato
tink
3

Com zsh, há o (q), (qq), (qqq), (qqqq)bandeiras expansão de variáveis que podem citar as variáveis de várias maneiras:

$ a=$'a b\nba\bc\u00e9\0'

$ printf '%s\n' $a
a b
bcé

$ printf %s $a | od -vtc
0000000   a       b  \n   b   a  \b   c 303 251  \0
0000013

$ printf '%s\n' ${(q)a}
a\ b$'\n'ba$'\b'cé$'\0'

$ printf '%s\n' ${(qq)a}
'a b
bcé'

$ printf '%s\n' ${(qqq)a}
"a b
bcé"

$ printf '%s\n' ${(qqqq)a}
$'a b\nba\bcé\0'

$ (){local LC_ALL=C; print -r -- ${(qqqq)a}}
$'a b\nba\bc\303\251\0'

No seu caso, você provavelmente desejaria um dos dois últimos.

Stéphane Chazelas
fonte
1

od -cnormalmente imprimirá caracteres normais, mas caracteres especiais (tabulação, nova linha etc.) e caracteres não imprimíveis como printfcódigo de escape.

Então:

$ echo -e asdf\\nghjk\\003foo | od -c -An
   a   s   d   f  \n   g   h   j   k 003   f   o   o  \n

O -Andiz odpara não emitir o endereço.

Brian Minton
fonte
-1

Use o printfcomando Por exemplo:

printf "Hello\nthis is my line

irá produzir

Hello
this is my line
Lazuardi N Putra
fonte
1
É o mesmo que echo -e, estou procurando o inverso .
drs
você pode me dar um exemplo específico?
Lazuardi N Putra