bash允许$'string'
扩展。我的man bash
说:
$'string'
形式的单词是专门处理的。 该单词扩展为string
,替换为ANSI C标准指定的反斜杠转义字符。 反斜杠转义序列(如果存在)按如下方式解码:
\a
警报(铃声)
\b
退格\e
\E
逃脱角色
\f
表格Feed 新\n
新行\r
回车
\t
水平标签
\v
垂直标签
\
反斜杠\'
单引号
\"
双引号\nnn
八位字符,其值为八进制值nnn
(一到三位数)
\xHH
八位字符,其值为十六进制值HH
(一个或两个十六进制数字)
\cx
控件 -x
字符
展开的结果是单引号,好像美元符号不存在一样。
但是为什么bash没有将$'\0'
和$'\x0'
转换为空字符?
有记录吗?有原因吗? (这是一个功能或限制,甚至是一个错误吗?)
$ hexdump -c <<< _$'\0'$'\x1\x2\x3\x4_'
0000000 _ 001 002 003 004 _ \n
0000007
echo
给出了预期的结果:
> hexdump -c < <( echo -e '_\x0\x1\x2\x3_' )
0000000 _ \0 001 002 003 _ \n
0000007
我的bash版
$ bash --version | head -n 1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
为什么echo $'foo\0bar'
的行为不是echo -e 'foo\0bar'
?
答案 0 :(得分:24)
这是一个限制。 bash
不允许字符串值包含内部NUL字节。
Posix(和C)字符串不能包含内部NUL。例如,请参阅字符串的Posix definition(强调添加):
3.92字符串
连续的字符序列以结尾,包括第一个空字节。
类似地,标准C对字符串中的NUL字符是合理明确的:
§5.2.1p2...所有位都设置为0的字节,称为空字符,应存在于基本执行字符集中;它用于终止字符串。
Posix明确禁止在文件名(XBD 3.170)或环境变量中使用NUL(和/
)(XBD 8.1“...被视为以空字节结尾。”
在这种情况下,shell命令语言(包括bash)倾向于使用相同的字符串定义,作为由单个NUL终止的非NUL字符序列。
当然,您可以通过bash管道自由传递NUL,并且没有什么能阻止您将shell变量分配给输出NUL字节的程序的输出。但是,根据Posix(XSH 2.6.3“如果输出包含任何空字节,则行为未指定。”),后果是“未指定的”。在bash中,除非使用bash的C-escape语法($'\0'
)将NUL插入到字符串中,否则将删除NUL,在这种情况下,NUL将最终终止该值。
实际上,请考虑以下两种尝试将NUL插入实用程序stdin
的方法之间的区别:
$ # Prefer printf to echo -n
$ printf $'foo\0bar' | wc -c
3
$ printf 'foo\0bar' | wc -c
7
$ # Bash extension which is better for strings which might contain %
$ printf %b 'foo\0bar' | wc -c
7
答案 1 :(得分:5)
但为什么bash不会将
$'\0'
和$'\x0'
转换为空字符?
因为空字符终止了字符串。
$ echo $'hey\0you'
hey
答案 2 :(得分:3)
这是一个空字符,但它取决于你的意思。
null字符表示一个空字符串,这是您展开它时得到的。这是一个特例,我认为这是由文档暗示的,但没有实际说明。
在C二进制文件中,零'\0'
终止一个字符串,它本身也代表一个空字符串。 Bash是用C语言编写的,所以可能就是这样。
编辑:POSIX在许多地方提到一个空字符串。在“基本定义”中,它将空字符串定义为:
3.146空字符串(或空字符串)
一个字符串,其第一个字节是空字节。