Bash 为什么$'\0';或$'\x0';是空字符串吗?应为空字符,isn';不是吗?
允许Bash 为什么$'\0';或$'\x0';是空字符串吗?应为空字符,isn';不是吗?,bash,string,echo,expansion,dollar-sign,Bash,String,Echo,Expansion,Dollar Sign,允许$”字符串“扩展。我的manbash说: 对$”字符串形式的单词进行特殊处理。 单词扩展为字符串,并按照ANSI C标准的规定替换反斜杠转义字符。 反斜杠转义序列(如果存在)解码如下: \a警报(铃声) \b退格 \e \E转义字符 \f表单提要 \n新行 \r回车 \t水平选项卡 \v垂直选项卡 \反斜杠 \'单引号 \”双引号 \nnn其值为八进制值的八位字符nnn(一到三位) \xHH其值为十六进制值的八位字符HH(一个或两个十六进制数字) \cxa控件-x字符 扩展后的结果是单引号,
$”字符串“
扩展。我的manbash
说:
对$”字符串形式的单词进行特殊处理。
单词扩展为字符串
,并按照ANSI C标准的规定替换反斜杠转义字符。
反斜杠转义序列(如果存在)解码如下:
\a
警报(铃声)
\b
退格
\e
\E
转义字符
\f
表单提要
\n
新行
\r
回车
\t
水平选项卡
\v
垂直选项卡
\
反斜杠
\'
单引号
\”
双引号
\nnn
其值为八进制值的八位字符nnn
(一到三位)
\xHH
其值为十六进制值的八位字符HH
(一个或两个十六进制数字)
\cx
a控件-x
字符
扩展后的结果是单引号,就好像美元符号不存在一样
但是为什么不将$'\0'
和$'\x0'
转换为空字符?
它有文档记录吗?有原因吗?(它是一个特性还是一个限制,甚至是一个bug?)
我的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'
不同?它是一个空字符,但这取决于您的意思
空字符表示一个空字符串,这是您在展开它时得到的。这是一个特殊情况,我认为文档中暗示了这一点,但实际上没有说明
在C中,二进制零“\0”
终止一个字符串,并且它本身也表示一个空字符串。Bash是用C编写的,因此它可能就是这样
编辑:POSIX在许多地方提到空字符串。在“基本定义”中,它将空字符串定义为:
3.146空字符串(或空字符串)
第一个字节为空字节的字符串
但是为什么bash不将$'\0'
和$'\x0'
转换为空字符呢
因为空字符终止字符串
$ echo $'hey\0you'
hey
这是一个限制。bash
不允许字符串值包含内部NUL字节
Posix(和C)字符串不能包含内部NUL。例如,请参阅字符串的名称(添加了强调符号):
3.92字符串
以结尾并包含第一个空字节的连续字符序列
同样,标准C对于字符串中的NUL字符也相当明确:
§5.2.1p2…基本执行字符集中应存在一个所有位均设置为0的字节,称为空字符;它用于终止字符串
Posix明确禁止在文件名(XBD 3.170)或环境变量(XBD 8.1)中使用NUL(和/
)“……被视为以空字节结尾。”
在这种情况下,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
问得好!可能是Posix的问题?祝你好运。谢谢你的回答。我在使用netcat测试服务器的SGCI接口时遇到了同样的问题。SCGI头有NUL字符。在阅读了这里,特别是关于使用管道的建议后,我开发了一个解决方法。我使用了octal 377(ASCII 255)在需要NUL字符的地方,然后通过tr将字符串传递到netcat xmlreq='system.client版本'scgihdr=CONTENT_LENGTH$'\377'${{xmlreq}$'\377'SCGI$'\377'1$'\377'echo-n${{scgihdrGreat info.Re:“没有任何东西可以阻止您将shell变量分配给输出NUL的程序的输出-值得指出的是,变量的值总是在遇到第一个NUL时被截断。Re“如果使用bash的反斜杠转义序列($'\0')将NUL插入字符串,它将终止该值。”-澄清一下:在另一个字符串中插入$'\0'
不会终止整个字符串,而只是忽略$'\0'
;例如,a$'\0'b
->ab
;在$'.
中插入\0
,但是,会在那里切断该字符串;例如,$'a\0b'
-@mklemt两年前这是错的。谢谢。现在我相信已经修复了。谢谢更新。将命令输出重新分配给变量:鉴于bash
变量值在内部存储为C字符串,它们永远不能包含
$ echo $'hey\0you'
hey
$ # 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