Quel est l'inverse de l'écho -e?

13

Si j'ai une chaîne avec des caractères non imprimables, de nouvelles lignes ou des tabulations, est-ce que je peux utiliser echopour imprimer cette chaîne et afficher les codes de ces caractères (par exemple, \npour la nouvelle ligne, \bpour le retour arrière)?

drs
la source
2
vous pouvez utiliser la commande printf, voir man printf
PersianGulf
12
e- ohce* rimshot *
David Richerby
3
printf '%q' "$str"affichera la chaîne échappée. Je n'ajoute pas cela comme réponse car ce n'est pas la même forme d'échappement qui echo -eutilise - plutôt, elle est destinée à être sécurisée par les évaluations - mais (1) c'est assez bon si votre objectif est la lisibilité humaine, (2) c'est assez bon si votre objectif est la génération de shell sécurisée, et (3) echo -eest mauvais et mauvais de toute façon (si vous lisez la spécification POSIX, vous verrez que printf est la façon préférée de faire le formatage des chaînes, et echo -en'est pas garanti par POSIX de base à tout).
Charles Duffy

Réponses:

7

Il existe de nombreuses façons de procéder. Les deux plus portables que je connaisse sont sedet od- ils sont tous les deux POSIX.

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

Il aime ... le readstyle s'échappe - style C.

PRODUCTION

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

od est un peu plus 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 vous voulez savoir quelles sont toutes ces options, vous pouvez regarder man od, mais je précise que je veux deux types d'échappements - les -t céchappements avec barre oblique inverse et les -t acaractères nommés. L' -woption utilisée ci-dessus n'est pas spécifiée par POSIX.

Et voici une petite fonction shell qui affichera de manière portable les valeurs octales de chaque octet dans ses arguments - qui, bien sûr, odpourraient également fonctionner avec -t o:

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

C'est simple. C'est un peu plus compliqué. Il devrait cependant être capable de faire ce que les printf -qimplémentations spécifiques au shell peuvent faire.

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

En utilisant l'exemple de chaîne précédente avec un peu plus:

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

PRODUCTION

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

Ce n'est que légèrement différent. Vous remarquerez peut-être qu'il y a un supplément 0et un \backslash supplémentaire . Cela permet de traduire facilement un readou un %b printfargument. Par exemple:

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

PRODUCTION

<\%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
la source
@ StéphaneChazelas Il ne fera toujours que des caractères codés sur un octet, mais il est à espérer qu'il est moins susceptible de bousiller maintenant.
mikeserv
1
Permettez-moi de vous amener à la barre des 10 000 :)
Ramesh
Woohoo !!!!!!!!!
slm
@slm - laissez-moi deviner .. Vous avez vraiment aimé le proctal?
mikeserv
@ StéphaneChazelas - avez-vous une idée bsq()- manque-t-il quelque chose? Je demande parce que je ne suis pas entièrement confiant sur les contre-obliques.
mikeserv
12

Lorsque vous supprimez le -ecommutateur à echo, dans bashet à condition que l' xpg_echooption n'ait pas été activée, il doit imprimer les chaînes comme rien de plus que leur texte d'origine. Donc, \net \tapparaîtrait comme littéralement cela.

Exemple

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

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

Vous pouvez également utiliser la printfcommande intégrée de ksh93, zshou bashpour le définir également.

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

( bashsortie montrée ci-dessus. Il y a quelques variations selon le shell).

extrait dehelp printf enbash

%q citer l'argument d'une manière qui peut être réutilisée comme entrée shell

slm
la source
1
Ce n'est pas printf %qcela qui tronque les \ns finaux , c'est la $()capture de sortie qui les supprime.
ecatmur
@ecatmur - merci je l'ai écrit tard dans la nuit et je n'ai pas essayé de le déboguer plus loin. Vous auriez raison, c'est le sous-shell qui les retire. Voici une raison: unix.stackexchange.com/questions/17747/…
slm
... de toute façon, courir printfà l' intérieur d'un sous-shell pour capturer sa sortie est idiot, car printf -v varnameil mettra la sortie directement dans une variable, aucun sous-shell impliqué.
Charles Duffy
@CharlesDuffy - Je ne vous suis pas, je ne suis pas en cours d'exécution printfdans un sous-shell, je suis en cours d'exécution echodans un, uniquement pour démontrer que vous pouvez prendre la sortie de caractères spéciaux echoet la reconvertir en notation échappée.
slm
@slm, c'était une réponse au premier commentaire (enfin, le code auquel le premier commentaire a répondu), pas le code tel que je l'ai trouvé maintenant. Si j'ai déduit quelque chose d'inexact sur l'état d'édition précédent, mes excuses.
Charles Duffy
5

Vous pourriez utiliser quelque chose comme,

$ cat filename
Ramesh is testing
New Line        is

Maintenant, vous pourriez faire quelque chose comme,

$ cat -A filename

Production

Ramesh is testing$
New Line ^Iis $

Un autre test général sans aucun fichier est comme,

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

La commande ci-dessus produit la sortie comme,

Hello^Iworld.$

Les références

Ramesh
la source
4
Ou, dans les implémentations non-GNU de chat, par exemple MacOS / X, prenez votre chat chez le vétérinaire ... chat -vet
Tink
3

Avec zsh, il y a les (q), (qq), (qqq), (qqqq)drapeaux d'expansion variables qui peuvent citer les variables de différentes façons:

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

Dans votre cas, vous voudrez probablement l'un des deux derniers.

Stéphane Chazelas
la source
1

od -cimprime normalement les caractères normaux, mais les caractères spéciaux (tabulation, retour à la ligne, etc.) et les caractères non imprimables comme printfcode d'échappement.

Donc:

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

Le -Andit odde ne pas sortir l'adresse.

Brian Minton
la source
-1

Utilisez la printfcommande. Par exemple:

printf "Hello\nthis is my line

affichera

Hello
this is my line
Lazuardi N Putra
la source
1
C'est la même chose que echo -e, je cherche l' inverse .
drs
pouvez-vous me donner un exemple précis?
Lazuardi N Putra,