¿Cuál es el reverso de echo -e?

13

Si tengo una cadena con caracteres no imprimibles, nuevas líneas o pestañas, ¿hay alguna forma que pueda usar echopara imprimir esta cadena y mostrar códigos para estos caracteres (por ejemplo, \npara una nueva línea, \bpara retroceder)?

drs
fuente
2
puede usar el comando printf, vea man printf
PersianGulf
12
e- ohce* rimshot *
David Richerby
3
printf '%q' "$str"imprimirá la cadena escapó. No estoy agregando esto como respuesta, ya que no es la misma forma de escape que se echo -eusa, sino que está destinado a ser evaluado con seguridad, pero (1) es lo suficientemente bueno si su objetivo es la legibilidad humana, (2) es lo suficientemente bueno si su objetivo es la generación segura de shell, y (3) echo -ees Malo e Incorrecto de todos modos (si lee la especificación POSIX, verá que printf es la forma preferida de formatear cadenas y echo -eno está garantizado por POSIX de línea de base en todos).
Charles Duffy

Respuestas:

7

Hay muchas maneras de hacer esto. Los dos más portátiles que conozco son sedy od- ambos son POSIX.

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

Le gusta ... readescapes de estilo - C-style.

SALIDA

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

od es un poco más configurable ...

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

Si quieres saber en qué opciones puedes mirar man od, pero especifico que quiero dos tipos de escapes: los -t cescapes de barra invertida y los -t acaracteres nombrados. La -wopción utilizada anteriormente no está especificada en POSIX.

Y aquí hay una pequeña función de shell que imprimirá de forma portátil los valores octales de cada byte en sus argumentos, que, por supuesto, también odpodrían manejarse con -t o:

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

Esa es una simple. Esto es un poco más complicado. Sin printf -qembargo, debería poder hacer lo que pueden hacer las implementaciones específicas de shell .

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 una cadena de ejemplo anterior con un poco adicional:

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

SALIDA

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

Es solo un poco diferente. Puede notar que hay 0una \bbarra extra y una barra extra . Esto es para permitir una fácil traducción a readun %b printfargumento. Por ejemplo:

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

SALIDA

<\%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
fuente
@ StéphaneChazelas Todavía solo hará caracteres de un byte, pero con suerte es menos probable que se arruine ahora.
mikeserv
1
Déjame llevarte a la marca de 10k :)
Ramesh
Woohoo !!!!!!!!!
slm
@slm - déjame adivinar ... ¿Realmente te gustó el proctal?
mikeserv
@ StéphaneChazelas, ¿tiene alguna idea al bsq()respecto? ¿Le falta algo? Pregunto porque no estoy completamente seguro de las barras invertidas.
mikeserv
12

Cuando quite el -einterruptor a echo, in bash, y siempre que la xpg_echoopción no se haya habilitado, debería imprimir las cadenas como nada más que su texto original. Entonces, \ny \taparecería literalmente como eso.

Ejemplo

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

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

También puede usar el printfcomando incorporado de ksh93, zsho bashpara finalizar esto también.

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

(La bashsalida se muestra arriba. Hay algunas variaciones dependiendo del shell).

extracto dehelp printf enbash

%q cite el argumento de una manera que pueda reutilizarse como entrada de shell

slm
fuente
1
No es printf %qque esté truncando los \ns finales , es la $()captura de salida que los elimina.
ecatmur
@ecatmur: gracias escribí eso a altas horas de la noche y no había intentado depurarlo más. Estarías en lo correcto, es la subshell que los está quitando. He aquí una razón: unix.stackexchange.com/questions/17747/…
slm
... de todos modos, ejecutar printfdentro de una subshell para capturar su salida es una tontería, ya printf -v varnameque colocará la salida directamente en una variable, no implicará ninguna subshell.
Charles Duffy
@CharlesDuffy: no te estoy siguiendo, no estoy corriendo printfen una subshell, estaba corriendo echoen una, solo para demostrar que puedes tomar la salida de caracteres especiales echoy convertirla nuevamente a la notación escapada.
slm
@slm, esa fue una respuesta al primer comentario (bueno, el código al que respondió el primer comentario), no el código como lo encontré ahora. Si deduje algo inexacto sobre el estado de edición anterior, mis disculpas.
Charles Duffy
5

Podrías usar algo como,

$ cat filename
Ramesh is testing
New Line        is

Ahora, podrías hacer algo como,

$ cat -A filename

Salida

Ramesh is testing$
New Line ^Iis $

Otra prueba general sin ningún archivo es como,

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

El comando anterior produce el resultado como,

Hello^Iworld.$

Referencias

Ramesh
fuente
44
O, en implementaciones de cat no GNU, por ejemplo, MacOS / X, lleve a su gato al veterinario ... cat -vet
tink
3

Con zsh, hay el (q), (qq), (qqq), (qqqq)banderas expansión de variables que se pueden citar las variables de varias maneras:

$ 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'

En tu caso, probablemente quieras uno de los dos últimos.

Stéphane Chazelas
fuente
1

od -cimprimirá caracteres normales normalmente, pero caracteres especiales (tabulación, nueva línea, etc.) y caracteres no imprimibles como su printfcódigo de escape.

Entonces:

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

El -Anle dice odque no muestre la dirección.

Brian Minton
fuente
-1

Usa el printfcomando. Por ejemplo:

printf "Hello\nthis is my line

saldrá

Hello
this is my line
Lazuardi N Putra
fuente
1
Esto es lo mismo que echo -e, estoy buscando lo contrario .
drs
¿me puede dar un ejemplo específico?
Lazuardi N Putra