Si tengo una cadena con caracteres no imprimibles, nuevas líneas o pestañas, ¿hay alguna forma que pueda usar echo
para imprimir esta cadena y mostrar códigos para estos caracteres (por ejemplo, \n
para una nueva línea, \b
para retroceder)?
Hay muchas maneras de hacer esto. Los dos más portátiles que conozco son sed
y od
- ambos son POSIX.
printf '\n\r\b\t\033[01;31m' | sed -n l
Le gusta ... read
escapes de estilo - C-style.
$
\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 c
escapes de barra invertida y los -t a
caracteres nombrados. La -w
opció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 od
podrí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 -q
embargo, 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')"
'\n\r\\'\''b\t\0033[01;31m'
Es solo un poco diferente. Puede notar que hay 0
una \b
barra extra y una barra extra . Esto es para permitir una fácil traducción a read
un %b
printf
argumento. 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
<\%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 >$
proctal
?
bsq()
respecto? ¿Le falta algo? Pregunto porque no estoy completamente seguro de las barras invertidas.
Cuando quite el -e
interruptor a echo
, in bash
, y siempre que la xpg_echo
opción no se haya habilitado, debería imprimir las cadenas como nada más que su texto original. Entonces, \n
y \t
aparecería literalmente como eso.
$ 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 printf
comando incorporado de ksh93
, zsh
o bash
para finalizar esto también.
$ printf "%q\n" "$(echo -e "hi\t\tbye\n\nbye")"
$'hi\t\tbye\n\nbye'
(La bash
salida se muestra arriba. Hay algunas variaciones dependiendo del shell).
help printf
enbash
%q
cite el argumento de una manera que pueda reutilizarse como entrada de shell
printf %q
que esté truncando los \n
s finales , es la $()
captura de salida que los elimina.
printf
dentro de una subshell para capturar su salida es una tontería, ya printf -v varname
que colocará la salida directamente en una variable, no implicará ninguna subshell.
printf
en una subshell, estaba corriendo echo
en una, solo para demostrar que puedes tomar la salida de caracteres especiales echo
y convertirla nuevamente a la notación escapada.
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
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.
od -c
imprimirá caracteres normales normalmente, pero caracteres especiales (tabulación, nueva línea, etc.) y caracteres no imprimibles como su printf
có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 -An
le dice od
que no muestre la dirección.
Usa el printf
comando. Por ejemplo:
printf "Hello\nthis is my line
saldrá
Hello
this is my line
echo -e
, estoy buscando lo contrario .
e- ohce
* rimshot *printf '%q' "$str"
imprimirá la cadena escapó. No estoy agregando esto como respuesta, ya que no es la misma forma de escape que seecho -e
usa, 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 -e
es Malo e Incorrecto de todos modos (si lee la especificación POSIX, verá que printf es la forma preferida de formatear cadenas yecho -e
no está garantizado por POSIX de línea de base en todos).