echo -e的反向是什么?


13

如果我的字符串带有不可echo打印的字符,\n换行或制表符,是否可以使用一种方法来打印此字符串并显示这些字符的代码(例如,换行,\b退格)?


2
您可以使用printf命令,请参见man printf
PersianGulf

12
e- ohce*边敲击*
大卫Richerby

3
printf '%q' "$str"将输出转义的字符串。我并没有将其作为答案,因为它与echo -e使用的转义形式不同-而是旨在实现安全评估-但(1)如果您的目标是人类可读性就足够了,(2)如果您的目标是安全地生成Shell,并且(3)echo -e无论如何都是Evil And Wrong(如果您阅读POSIX规范,您会发现printf是进行字符串格式化的首选方法,并且echo -e基线POSIX不能保证这样做,则足够好了)所有)。
查尔斯·达菲

Answers:


7

有很多方法可以做到这一点。最便携的两块,我知道的是sedod-他们都是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,但我指定我想要两种转义符- -t c反斜杠转义-t a符和命名字符。-w上面使用的选项不是POSIX指定的。

这是一个小小的shell函数,它将可移植地打印出其参数中每个字节的八进制值-当然,它od也可以通过以下方式处理-t o

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

这很简单。这有点复杂。但是,它应该能够执行特定于Shell的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'

只是略有不同。您可能会注意到这里有一个额外的0和一个额外的\backslash。这是为了便于翻译为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 2014年

1
让我让您达到10k标记:)
Ramesh 2014年

哇!!!!!!!!!
slm

@slm-让我猜..您真的很喜欢proctal吗?
mikeserv 2014年

@StéphaneChazelas-您有什么想法bsq()吗-它丢失了什么吗?我问是因为我对反斜杠并不完全自信。
mikeserv 2014年

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内置命令ksh93zsh或者也可以使用此命令bash

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

bash上面显示的输出。具体取决于外壳)。

摘自help printfbash

%q 用可以作为shell输入重用的方式引用参数


1
不是printf %q尾随\ns被截断,而是$()输出捕获将其剔除。
ecatmur 2014年

@ecatmur-谢谢,我是在深夜写的,没有尝试进一步调试它。没错,是将它们剥离的子外壳。原因如下:unix.stackexchange.com/questions/17747/…–
slm

...无论如何,printf在子外壳内部运行以捕获其输出是很愚蠢的,因为printf -v varname它将直接将输出放入变量中,而不涉及子外壳。
查尔斯·达菲

@CharlesDuffy-我没有关注您,我没有printf在子外壳中运行,而是在一个子外壳中运行echo,纯粹是为了证明您可以从中获取特殊字符输出echo并将其转换回转义符号。
slm

@slm,这是对第一个注释的响应(嗯,第一个注释所响应的代码),而不是我现在发现的代码。如果我推断出有关先前编辑状态的不准确信息,我深表歉意。
查尔斯·达菲

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,把你的猫去看兽医... 猫-vet
天衣

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不输出地址。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.