Apa kebalikan dari echo -e?

13

Jika saya memiliki string dengan karakter yang tidak dapat echodicetak , baris baru, atau tab, apakah ada cara yang dapat saya gunakan untuk mencetak string ini dan menampilkan kode untuk karakter ini (misalnya, \nuntuk baris baru, \buntuk backspace)?

drs
sumber
2
Anda dapat menggunakan perintah printf, lihat man printf
PersianGulf
12
e- ohce* rimshot *
David Richerby
3
printf '%q' "$str"akan mencetak string lolos. Saya tidak menambahkan ini sebagai jawaban karena itu bukan bentuk melarikan diri yang sama yang echo -emenggunakan - lebih tepatnya, itu dimaksudkan untuk aman dari kesalahan - tetapi (1) itu cukup baik jika tujuan Anda adalah keterbacaan manusia, (2) itu cukup bagus jika sasaran Anda adalah menghasilkan shell yang aman, dan (3) echo -ebagaimanapun juga Jahat Dan Salah (jika Anda membaca spesifikasi POSIX, Anda akan melihat bahwa printf adalah cara yang disukai untuk melakukan pemformatan string, dan echo -etidak dijamin oleh POSIX dasar di semua).
Charles Duffy

Jawaban:

7

Ada banyak cara untuk melakukan ini. Dua yang paling portabel yang saya tahu adalah seddan od- keduanya POSIX.

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

Itu seperti ... readstyle escape - C-style.

KELUARAN

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

od sedikit lebih dapat dikonfigurasi ...

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

Jika Anda ingin tahu apa semua opsi yang Anda bisa lihat man od, tapi saya tentukan saya ingin dua jenis lolos - -t cbackslash lolos dan -t akarakter yang disebutkan. The -wpilihan yang digunakan di atas tidak POSIX-ditentukan.

Dan inilah fungsi shell kecil yang akan mencetak nilai oktal setiap byte dalam portablenya - yang tentu saja oddapat menangani -t o:

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

Itu yang sederhana. Ini sedikit lebih rumit. Seharusnya bisa melakukan apa yang bisa dilakukan oleh printf -qimplementasi spesifik 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/$$//'
)

Menggunakan contoh string dari sebelumnya dengan sedikit tambahan:

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

KELUARAN

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

Hanya sedikit berbeda. Anda mungkin memperhatikan ada tambahan 0dan tambahan \backslash. Ini untuk memungkinkan terjemahan yang mudah ke suatu readatau %b printfargumen. Sebagai contoh:

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

KELUARAN

<\%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
sumber
@ StéphaneChazelas Masih hanya akan melakukan karakter byte tunggal, tapi semoga saja ini tidak lagi kacau sekarang.
mikeserv
1
Biarkan saya membawa Anda ke tanda 10k :)
Ramesh
Woo hoo!!!!!!!!!
slm
@slm - coba saya tebak .. Anda benar-benar menyukai proctal?
mikeserv
@ StéphaneChazelas - apakah Anda memiliki pemikiran tentang bsq()- apakah ada yang hilang? Saya bertanya karena saya tidak sepenuhnya yakin tentang backslash.
mikeserv
12

Ketika Anda menghapus -esakelar ke echo, di bash, dan asalkan xpg_echoopsi belum diaktifkan, itu harus mencetak string sebagai tidak lebih dari teks aslinya. Jadi \ndan \takan muncul secara harfiah.

Contoh

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

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

Anda juga dapat menggunakan printfperintah bawaan ksh93, zshatau bashuntuk menyelesaikan ini juga.

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

( bashoutput ditunjukkan di atas. Ada beberapa variasi tergantung pada shell).

kutipan darihelp printf dalambash

%q mengutip argumen dengan cara yang dapat digunakan kembali sebagai input shell

slm
sumber
1
Bukan itu printf %qyang memotong trailing \n, melainkan $()tangkapan keluaran yang menghapusnya.
ecatmur
@ecatmur - terima kasih saya menulis itu larut malam dan belum mencoba untuk men-debug lebih lanjut. Anda benar, itu adalah subkulit yang menanggalkan mereka. Inilah alasannya: unix.stackexchange.com/questions/17747/…
slm
... bagaimanapun juga, menjalankan printfdi dalam subkulit untuk menangkap outputnya adalah konyol, karena printf -v varnameakan menempatkan output secara langsung ke dalam variabel, tidak ada subkulit yang terlibat.
Charles Duffy
@CharlesDuffy - Saya tidak mengikuti Anda, saya tidak menjalankan printfdalam subkulit, saya berjalan echodalam satu, murni untuk menunjukkan bahwa Anda dapat mengambil output karakter khusus dari echodan mengubahnya kembali ke notasi yang lolos.
slm
@slm, itu adalah tanggapan terhadap komentar pertama (baik, kode yang ditanggapi oleh komentar pertama), bukan kode seperti yang saya temukan sekarang. Jika saya menyimpulkan ada sesuatu yang tidak akurat tentang kondisi edit sebelumnya, permintaan maaf saya.
Charles Duffy
5

Anda bisa menggunakan sesuatu seperti,

$ cat filename
Ramesh is testing
New Line        is

Sekarang, Anda bisa melakukan sesuatu seperti,

$ cat -A filename

Keluaran

Ramesh is testing$
New Line ^Iis $

Pengujian umum lainnya tanpa file adalah,

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

Perintah di atas menghasilkan output sebagai,

Hello^Iworld.$

Referensi

Ramesh
sumber
4
Atau, di non-GNU implementasi kucing, misalnya MacOS / X, mengambil kucing Anda ke dokter hewan ... kucing -vet
tink
3

Dengan zsh, ada (q), (qq), (qqq), (qqqq)bendera ekspansi variabel yang dapat mengutip variabel dalam berbagai cara:

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

Dalam kasus Anda, Anda mungkin menginginkan salah satu dari dua yang terakhir.

Stéphane Chazelas
sumber
1

od -cakan mencetak karakter normal secara normal, tetapi karakter khusus (tab, baris baru, dll.) dan karakter yang tidak patut dicetak sebagai printfkode pelarian mereka .

Begitu:

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

The -Anmemberitahu odtidak keluaran alamat.

Brian Minton
sumber
-1

Gunakan printfperintah. Sebagai contoh:

printf "Hello\nthis is my line

akan menampilkan

Hello
this is my line
Lazuardi N Putra
sumber
1
Ini sama dengan echo -e, saya mencari yang sebaliknya .
drs
dapatkah Anda memberi saya contoh spesifik?
Lazuardi N Putra