Co to jest odwrotność echa -e?

13

Jeśli mam ciąg znaków z niedrukowalnymi znakami, nowymi wierszami lub tabulatorami, czy istnieje sposób echona wydrukowanie tego ciągu i pokazanie kodów dla tych znaków (np. \nDla nowego wiersza, \bdla backspace)?

dr
źródło
2
możesz użyć polecenia printf, patrz man printf
PersianGulf
12
e- ohce* rimshot *
David Richerby
3
printf '%q' "$str"wypisze znak ucieczki. Nie dodam tego jako odpowiedzi, ponieważ nie jest to ta sama forma ucieczki, która echo -eużywa - raczej ma być bezpieczna dla ewaluacji - ale (1) jest wystarczająco dobra, jeśli twoim celem jest czytelność dla ludzi, (2) to wystarczająco dobre, jeśli twoim celem jest bezpieczne generowanie powłoki, a (3) echo -ejest złe i złe w każdym razie (jeśli przeczytasz specyfikację POSIX, zobaczysz, że printf jest preferowanym sposobem formatowania łańcucha i echo -enie jest gwarantowane przez bazowe POSIX na wszystko).
Charles Duffy,

Odpowiedzi:

7

Można to zrobić na wiele sposobów. Najbardziej przenośne dwa, jakie znam, to sedi od- oba są POSIX.

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

To lubi ... readucieczki stylu - styl C.

WYNIK

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

od jest trochę bardziej konfigurowalny ...

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

Jeśli chcesz wiedzieć, w jakie te wszystkie opcje możesz zajrzeć man od, ale określam, że chcę dwóch rodzajów znaków ucieczki - znaków -t codwrotnego ukośnika i -t anazwanych postaci. -wOpcja nie jest używane powyżej POSIX określony.

A oto mała funkcja powłoki, która w przenośny sposób wypisuje wartości ósemkowe każdego bajtu w swoich argumentach - które oczywiście odmogłyby również obsługiwać -t o:

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

To jest proste. To jest trochę bardziej skomplikowane. Powinno być w stanie robić to, co printf -qmogą implementacje specyficzne dla powłoki .

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

Wykorzystując przykładowy ciąg z wcześniejszego z odrobiną dodatkowej:

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

WYNIK

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

Jest tylko nieco inny. Możesz zauważyć, że istnieje dodatkowy 0i dodatkowy \backslash. Ma to na celu umożliwienie łatwego tłumaczenia na argument readlub %b printfargument. Na przykład:

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

WYNIK

<\%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
źródło
@ StéphaneChazelas Nadal będzie robił tylko znaki jednobajtowe, ale mam nadzieję, że teraz jest mniej prawdopodobne, że się zepsuje.
mikeserv
1
Pozwól, że zabiorę Cię do 10 000 :)
Ramesh
Woohoo !!!!!!!!!
slm
@slm - niech zgadnę .. Naprawdę podobało ci się proctal?
mikeserv
@ StéphaneChazelas - czy masz jakieś przemyślenia na temat bsq()- czy czegoś brakuje? Pytam, ponieważ nie jestem całkowicie pewny co do odwrotnych ukośników.
mikeserv
12

Po usunięciu -eprzełącznika na echo, w bashi pod warunkiem, że xpg_echoopcja nie została włączona, łańcuchy powinny być drukowane jako nic więcej niż oryginalny tekst. Tak \ni \tpokazałby się dosłownie tak.

Przykład

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

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

Można również skorzystać z printfwbudowanego w dowodzenie ksh93, zshalbo bashfinagle to za dobrze.

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

( bashdane wyjściowe pokazano powyżej. Istnieje kilka odmian w zależności od powłoki).

fragmenthelp printf wbash

%q zacytuj argument w sposób, który może być ponownie wykorzystany jako dane wejściowe powłoki

slm
źródło
1
Nie chodzi o to, printf %qże obcinają końcowe \ns, lecz $()przechwytywanie danych wyjściowych, które je rozbiera.
ecatmur
@ ecatmur - dzięki, że napisałem to późno w nocy i nie próbowałem dalej debugować. Miałbyś rację, to ta podpowłoka usuwa je. Oto powód, dla którego: unix.stackexchange.com/questions/17747/…
slm
... w każdym razie uruchamianie printfwewnątrz podpowłoki w celu przechwytywania danych wyjściowych jest głupie, ponieważ printf -v varnameumieści dane wyjściowe bezpośrednio w zmiennej, bez udziału podpowłoki.
Charles Duffy,
@CharlesDuffy - Nie podążam za tobą, nie działam printfw podpowłoce, działałem echow jednym, tylko po to, aby pokazać, że możesz pobrać dane wyjściowe ze znaków specjalnych echoi przekonwertować je z powrotem na notację ucieczkową.
slm
@slm, to była odpowiedź na pierwszy komentarz (no cóż, kod, na który odpowiedział pierwszy komentarz), a nie kod taki, jaki go teraz znalazłem. Jeśli wywnioskowałem coś niedokładnego na temat stanu poprzedniej edycji, przepraszam.
Charles Duffy,
5

Możesz użyć czegoś takiego,

$ cat filename
Ramesh is testing
New Line        is

Teraz możesz zrobić coś takiego,

$ cat -A filename

Wynik

Ramesh is testing$
New Line ^Iis $

Kolejnym ogólnym testem bez plików jest:

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

Powyższe polecenie zwraca dane wyjściowe jako,

Hello^Iworld.$

Bibliografia

Ramesh
źródło
4
Lub, w implementacjach cat innych niż GNU, np. MacOS / X, zabierz swojego kota do weterynarza ... cat -vet
tink
3

Dzięki zsh, tam są (q), (qq), (qqq), (qqqq)zmienne flagi rozszerzeń, które mogą cytowanie zmiennych na różne sposoby:

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

W twoim przypadku prawdopodobnie chcesz jednego z dwóch ostatnich.

Stéphane Chazelas
źródło
1

od -cwypisze normalne znaki normalnie, ale znaki specjalne (tab, znak nowej linii itp.) i znaki niedrukowalne jako printfkod ucieczki.

Więc:

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

-AnMówi odnie wyjście adres.

Brian Minton
źródło
-1

Użyj printfpolecenia. Na przykład:

printf "Hello\nthis is my line

wyjdzie

Hello
this is my line
Lazuardi N Putra
źródło
1
To jest taka sama jak echo -eszukam na odwrocie .
drs
czy możesz podać mi konkretny przykład?
Lazuardi N Putra,