Bash 里的转义序列

在 Bash 里,一共有五个地方支持反斜杠开头的转义序列,包括两个内部命令 echo 和 printf 的参数里,字符串语法 $'...' 里,还有四个提示符变量 PS1-PS4 里,以及在 Readline 配置文件里(用来自定义键盘快捷键)。其中后两者不在本文的讨论范围内,我们只看看前三个命令/语法在对某些转义序列解释上的差异。

1. \?,\',\"

$'...' 会把反斜杠去掉,只分别输出问号,单引号,双引号这三个字符串本身,而 echo -e 会原样输出(保留反斜杠),也就是不把这三个东西当成转义序列。printf 要分两种情况来看,一种情况是转义序列出现在 printf 的格式字符串中,也就是出现在 printf 的第一个参数中,这种情况它的表现像 $'...',还有一种就是转义序列出现在与 printf 第一个参数里的 %b 格式指示符对应的随后的参数里的情况,这时候它的表现像 echo -e,下面看演示。

$ echo $'\?'$'\''$'\"'           # 反斜杠不见了

?'"

$ echo -e '\?'"\'"'\"'           # 原样输出

\?\'\"

$ printf '\?'"\'"'\"''\n'         # 表现的像 $'...'

?'"

$ printf '%b' '\?'"\'"'\"''\n'  # 表现的像 echo -e

\?\'\"

2. \nnn 和 \0nnn

$'...' 只支持 \nnn,而 echo -e 只支持 \0nnn。printf 还是要分两种情况来看,出现在格式字符串中的表现像 $'...',出现在 %b 的参数里是,同时支持 \nnn 和 \0nnn 两种形式,下面看演示。

$ echo $'\100' $'\0100'       # 第二个参数里的 \0100 被解释成了 \010 和 0,所以 echo 分别输出了 @,\010,0 这三个字符,第二个字符串就是 \b,它不可见

@ 0

$ echo -e '\100' '\0100'       # \100 原样输出

\100 @

$ printf '\100 \0100\n'        # \010 也就是退格符删掉了中间的空格,所以 @ 和 0 之间紧挨着 

@0

$ printf '%b' '\100\0100\n'  # 两种语法都支持

@@

3. \c

$'...' 会把 \c 以及它后面的那个字符(x)合起来看成一个转义序列,解义后的值会是个控制字符(ascii 码在 0 到 31 之间的字符),其解义算法是这样的:chr(ord(x) & 31)。而 echo -e 会把 \c 看成是字符串的终结符号,在 \c 之后的所有字符都会被丢弃掉,对应于 c 语言字符串中表示字符串结尾的 \0 字符,其底层实现也的确是把 \c 解义成了 \0(Bash 是用 c 语言写的)。printf 还是要分两种情况来看,如果出现在格式字符串中,\c 会原样输出,如果出现在 %b 的参数里是,\c 的表现像 echo -e,下面看演示。

$ echo $'\c*'                     # \c* 解义 之后是 \n,所以下面会有两个空行

 

 

$ echo -e 'hello\cworld'      # world 以及最后的换行符都被吞掉了

hello

$ printf '\c*\n'                   # \c 原样输出 

\c*

$ printf '%b' 'hello\cworld'  # 表现的和 echo -e 一样

hello

总结

上面讲的所有这些在 Bash Manual 里都有提到,只是有些点说的比较隐含。你只要知道这三种用来输出转义序列的命令/语法是有细微差别的就可以了,不要去尝试记忆这些差别,因为你可能一辈子也遇不上。同时在看 Bash Manual 的时候发现讲 $'...' 的章节漏掉了对 \? 这个转义序列的记载,虽然不是什么大事,但还是报了个 bug http://comments.gmane.org/gmane.comp.shells.bash.bugs/24127

posted @ 2015-09-03 11:47  紫云飞  阅读(1411)  评论(0编辑  收藏  举报