สิ่งที่ตรงกันข้ามของ echo -e?


13

หากฉันมีสตริงที่มีอักขระที่ไม่สามารถechoพิมพ์ได้บรรทัดใหม่หรือแท็บมีวิธีที่ฉันสามารถใช้พิมพ์สตริงนี้และแสดงรหัสสำหรับอักขระเหล่านี้ (เช่น\nสำหรับบรรทัดใหม่\bสำหรับ backspace) หรือไม่


2
คุณสามารถใช้คำสั่ง printf ดู man printf
PersianGulf

12
e- ohce* rimshot *
David Richerby

3
printf '%q' "$str"จะพิมพ์สตริงหนี ฉันไม่ได้เพิ่มสิ่งนี้เป็นคำตอบเนื่องจากมันไม่ใช่รูปแบบการหลบหนีที่echo -eใช้ - แต่มันมีจุดประสงค์เพื่อความปลอดภัย - แต่ (1) มันดีพอถ้าเป้าหมายของคุณคือความสามารถในการอ่านของมนุษย์ (2) ดีพอถ้าเป้าหมายของคุณคือการสร้างเชลล์ที่ปลอดภัยและ (3) echo -eคือ Evil And Wrong อย่างใดอย่างหนึ่ง (ถ้าคุณอ่านข้อมูลจำเพาะ POSIX คุณจะเห็นว่า printf เป็นวิธีที่เหมาะสมในการจัดรูปแบบสตริงและecho -eไม่รับประกันโดย POSIX พื้นฐานที่ ทั้งหมด)
Charles Duffy

คำตอบ:


7

มีหลายวิธีในการทำเช่นนี้ สองแบบพกพาที่สุดที่ฉันรู้sedและเป็นod- ทั้งสอง POSIX

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

มันไม่เหมือน ... readสไตล์การหลบหนี - สไตล์ C

เอาท์พุท

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

od สามารถกำหนดค่าได้มากกว่านี้เล็กน้อย ...

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

หากคุณต้องการทราบว่าคุณสามารถดูตัวเลือกเหล่านี้ได้ทั้งหมดman odแต่ฉันระบุว่าฉันต้องการ Escape สองประเภท - -t cBackslash Escape และ-t aอักขระที่มีชื่อ -wตัวเลือกที่ใช้ข้างต้นไม่ POSIX ระบุ

และนี่คือฟังก์ชั่นเชลล์ตัวเล็ก ๆ ที่จะพิมพ์ค่าฐานแปดของแต่ละไบต์ในอาร์กิวเมนต์ของมันซึ่งแน่นอนว่าodอาจรองรับเช่นกันกับ-t o:

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

นั่นเป็นเรื่องง่าย มันซับซ้อนกว่านี้เล็กน้อย มันควรจะสามารถทำสิ่งที่การprintf -qใช้งานเฉพาะเชลล์สามารถทำได้

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

การใช้สตริงตัวอย่างออกจากก่อนหน้านี้กับเพิ่มเติมเล็กน้อย:

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

เอาท์พุท

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

มันแตกต่างกันเล็กน้อยเท่านั้น คุณอาจสังเกตเห็นว่ามีackslash พิเศษ0และพิเศษ \bนี่คือเพื่อให้ง่ายสำหรับการแปลreadเป็น%b printfอาร์กิวเมนต์หรือ ตัวอย่างเช่น:

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

@ StéphaneChazelasมันจะยังคงทำตัวอักษรแบบไบต์เดียวเท่านั้น แต่หวังว่าจะมีโอกาสน้อยลงที่จะพลาด
mikeserv

1
ผมขอพาคุณไปที่เครื่องหมาย 10k :)
Ramesh

วู้ !!!!!!!!!
slm

@slm - ให้ฉันเดา .. คุณชอบproctalหรือไม่
mikeserv

@ StéphaneChazelas - คุณมีความคิดbsq()อะไรหรือเปล่า - มันหายไปหมดรึเปล่า? ฉันถามเพราะฉันไม่มั่นใจเกี่ยวกับแบ็กสแลชทั้งหมด
mikeserv

12

เมื่อคุณลบ-eสวิทช์ไปที่echo, ในbash, และหากxpg_echoไม่ได้เปิดใช้งานตัวเลือก, มันควรจะพิมพ์สตริงเป็นอะไรมากกว่าข้อความต้นฉบับ ดังนั้น\nและ\tจะปรากฏเป็นอักษรว่า

ตัวอย่าง

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

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

นอกจากนี้คุณยังสามารถใช้printfในตัวคำสั่งของksh93, zshหรือbashเพื่อ finagle นี้เช่นกัน

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

( bashเอาต์พุตที่แสดงด้านบนมีความแตกต่างบางอย่างขึ้นอยู่กับเปลือก)

ตัดตอนมาจากhelp printfในbash

%q อ้างอาร์กิวเมนต์ในวิธีที่สามารถนำมาใช้ใหม่เป็นอินพุตเชลล์


1
ไม่ใช่printf %qว่าจะตัดทอนท้าย\nของมัน$()ออก แต่เป็นการจับเอาท์พุทที่ดึงออกมา
ecatmur

@ecatmur - ขอบคุณที่ฉันเขียนตอนดึกและไม่ได้พยายามที่จะแก้ปัญหามันต่อไป คุณต้องการถูกต้องมันเป็น subshell ที่ลอกออก นี่คือเหตุผลว่าทำไม: unix.stackexchange.com/questions/17747/…
slm

... อย่างไรก็ตามการเรียกใช้printfภายใน subshell เพื่อจับเอาท์พุทนั้นมันงี่เง่าเพราะprintf -v varnameจะทำให้เอาท์พุทลงในตัวแปรโดยตรงไม่ต้องมี subshell
Charles Duffy

@CharlesDuffy - ฉันไม่ได้ติดตามคุณฉันไม่ได้ทำงานprintfใน subshell ฉันทำงานechoเป็นหนึ่งเดียวเพื่อแสดงให้เห็นว่าคุณสามารถใช้อักขระพิเศษจากechoและแปลงกลับเป็นสัญ
slm

@slm นั่นคือการตอบกลับความคิดเห็นแรก (ดีรหัสที่ความคิดเห็นแรกตอบกลับ) ไม่ใช่รหัสที่ฉันพบตอนนี้ หากฉันอนุมานบางสิ่งที่ไม่ถูกต้องเกี่ยวกับสถานะการแก้ไขก่อนหน้านี้ฉันขอโทษ
Charles Duffy

5

คุณสามารถใช้สิ่งที่ชอบ

$ cat filename
Ramesh is testing
New Line        is

ตอนนี้คุณสามารถทำสิ่งที่ชอบ

$ cat -A filename

เอาท์พุต

Ramesh is testing$
New Line ^Iis $

การทดสอบทั่วไปอื่นที่ไม่มีไฟล์ใด ๆ คือ

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

คำสั่งดังกล่าวให้ผลผลิตเป็น

Hello^Iworld.$

อ้างอิง


4
หรือในการใช้งานของแมวที่ไม่ใช่ GNU เช่น MacOS / X พาแมวไปหาสัตว์แพทย์ ... cat -vet
tink

3

ด้วยzshมีเป็น(q), (qq), (qqq), (qqqq)ธงขยายตัวตัวแปรที่สามารถพูดตัวแปรในรูปแบบต่างๆ:

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

ในกรณีของคุณคุณอาจต้องการหนึ่งในสองอันสุดท้าย


1

od -cจะพิมพ์อักขระปกติตามปกติ แต่อักขระพิเศษ (แท็บขึ้นบรรทัดใหม่ ฯลฯ ) และอักขระที่ไม่สามารถพิมพ์ได้เป็นprintfรหัสยกเว้น

ดังนั้น:

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

การ-Anบอกodให้ไม่ส่งออกที่อยู่


-1

ใช้printfคำสั่ง ตัวอย่างเช่น:

printf "Hello\nthis is my line

จะส่งออก

Hello
this is my line

1
นี่คือเดียวกันเป็นecho -eฉันกำลังมองหาแบบย้อนกลับ
drs

คุณสามารถยกตัวอย่างเฉพาะให้ฉันได้ไหม
Lazuardi N Putra
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.