Mặt trái của echo -e là gì?


13

Nếu tôi có một chuỗi với các ký tự không thể in, dòng mới hoặc tab, có cách nào tôi có thể sử dụng echođể in chuỗi này và hiển thị mã cho các ký tự này (ví dụ: \ncho dòng mới, \bcho backspace) không?


2
bạn có thể sử dụng lệnh printf, xem man printf
tiếng Ba Tư

12
e- ohce* rimshot *
David Richerby

3
printf '%q' "$str"sẽ in chuỗi thoát. Tôi không thêm câu trả lời này vì đây không phải là hình thức thoát tương tự mà echo -esử dụng - đúng hơn, nó có ý định an toàn - nhưng (1) nó đủ tốt nếu mục tiêu của bạn là khả năng đọc của con người, (2) đủ tốt nếu mục tiêu của bạn là tạo vỏ an toàn và (3) echo -edù sao cũng là Ác và Sai (nếu bạn đọc thông số POSIX, bạn sẽ thấy printf là cách ưa thích để thực hiện định dạng chuỗi và echo -ekhông được đảm bảo bởi POSIX cơ bản tại tất cả).
Charles Duffy

Câu trả lời:


7

Có rất nhiều cách để làm điều này. Hai thiết bị di động nhất mà tôi biết là sedod- cả hai đều là POSIX.

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

Nó không thích ... readthoát kiểu - kiểu C.

ĐẦU RA

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

od cấu hình hơn một chút ...

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

Nếu bạn muốn biết tất cả các tùy chọn đó bạn có thể xem trong đó man od, nhưng tôi chỉ định tôi muốn có hai loại thoát - -t cdấu gạch chéo ngược thoát và -t aký tự được đặt tên. Các -wtùy chọn sử dụng trên không phải là POSIX chỉ định.

Và đây là một hàm shell nhỏ có thể in ra các giá trị bát phân của từng byte trong các đối số của nó - tất nhiên, odcó thể xử lý tốt như -t osau:

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

Đó là một điều đơn giản. Điều này phức tạp hơn một chút. Nó sẽ có thể làm những gì các printf -qtriển khai cụ thể vỏ có thể, mặc dù.

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

Sử dụng chuỗi ví dụ từ trước đó với một chút bổ sung:

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

ĐẦU RA

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

Nó chỉ hơi khác một chút. Bạn có thể nhận thấy có thêm 0một \backslash. Điều này là để cho phép dễ dàng dịch sang một readhoặc một %b printfđối số. Ví dụ:

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

ĐẦU RA

<\%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 >$

@ StéphaneChazelas Nó vẫn sẽ chỉ tạo ra các ký tự byte đơn, nhưng hy vọng nó ít có khả năng làm hỏng ngay bây giờ.
mikeerv

1
Hãy để tôi đưa bạn đến mốc 10k :)
Ramesh

Woohoo !!!!!!!!!
slm

@slm - Hãy để tôi đoán .. Bạn thực sự thích proctal?
mikeerv

@ StéphaneChazelas - bạn có suy nghĩ bsq()gì không - có thiếu gì không? Tôi hỏi bởi vì tôi không hoàn toàn tự tin về dấu gạch chéo ngược.
mikeerv

12

Khi bạn loại bỏ công -etắc sang echo, trong bashvà với điều kiện xpg_echotùy chọn chưa được bật, nó sẽ in các chuỗi không có gì nhiều hơn văn bản gốc của chúng. Vì vậy, \n\tsẽ hiển thị như nghĩa đen đó.

Thí dụ

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

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

Bạn cũng có thể sử dụng printfbuilt-in lệnh của ksh93, zshhoặc bashcách để có lợi này là tốt.

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

( bashđầu ra được hiển thị ở trên. Có một số biến thể tùy thuộc vào vỏ).

trích từhelp printf trongbash

%q trích dẫn đối số theo cách có thể được sử dụng lại làm đầu vào shell


1
Đó không phải printf %qlà cắt ngắn các dấu \n, đó là bản ghi $()đầu ra loại bỏ chúng.
ecatmur

@ecatmur - cảm ơn tôi đã viết nó vào tối muộn và đã không cố gắng gỡ lỗi thêm. Bạn đã đúng, đó là lớp vỏ con tước bỏ chúng. Đây là một lý do tại sao: unix.stackexchange.com/questions/17747/ trên
slm

... Dù sao đi nữa, việc chạy printfbên trong một lớp con để nắm bắt đầu ra của nó là điều ngớ ngẩn, vì printf -v varnamesẽ đưa đầu ra trực tiếp vào một biến, không có phần con nào liên quan.
Charles Duffy

@CharlesDuffy - Tôi không theo dõi bạn, tôi không chạy printftrong một mạng con, tôi đang chạy echotrong một, hoàn toàn để chứng minh rằng bạn có thể lấy đầu ra ký tự đặc biệt từ đó echovà chuyển nó trở lại ký hiệu thoát.
slm

@slm, đó là phản hồi cho nhận xét đầu tiên (tốt, mã mà nhận xét đầu tiên đã phản hồi), không phải mã như tôi tìm thấy bây giờ. Nếu tôi suy luận điều gì đó không chính xác về trạng thái chỉnh sửa trước đó, tôi xin lỗi.
Charles Duffy

5

Bạn có thể sử dụng một cái gì đó như,

$ cat filename
Ramesh is testing
New Line        is

Bây giờ, bạn có thể làm một cái gì đó như,

$ cat -A filename

Đầu ra

Ramesh is testing$
New Line ^Iis $

Một thử nghiệm chung khác mà không có bất kỳ tập tin nào là,

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

Lệnh trên mang lại đầu ra là,

Hello^Iworld.$

Người giới thiệu


4
Hoặc, trong các triển khai không phải GNU của mèo, ví dụ MacOS / X, hãy đưa mèo của bạn đến bác sĩ thú y ... mèo -vet
tink

3

Với zsh, có những (q), (qq), (qqq), (qqqq)cờ mở rộng biến mà có thể trích dẫn các biến trong nhiều cách khác nhau:

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

Trong trường hợp của bạn, bạn có thể muốn một trong hai cuối cùng.


1

od -csẽ in các ký tự bình thường, nhưng các ký tự đặc biệt (tab, dòng mới, v.v.) và các ký tự không thể in thành printfmã thoát.

Vì thế:

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

Các -Annói odkhông ra địa chỉ.


-1

Sử dụng printflệnh. Ví dụ:

printf "Hello\nthis is my line

sẽ xuất

Hello
this is my line

1
Điều này cũng giống như echo -e, tôi đang tìm kiếm điều ngược lại .
drs

bạn có thể cho tôi ví dụ cụ thể?
Lazuardi N Putra
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.