正如其他人所说,你不能存储或使用 NUL 字符:
然而,你可以处理任何二进制数据(包括 NUL 字符):
因此,回答你的最后一个问题:
有人能给我指点一下,如何高效地存储或处理包含 \0 字符的字符串,而不会丢失任何(元)字符吗?
你可以使用文件或管道来高效地存储和处理任何带有任何元字符的字符串。
如果你计划处理数据,还应注意以下内容:
- 只有 NUL 字符会被变量和命令行参数吃掉,你可以检查一下。
- 要注意命令替换(如
$(command..)
或 `command..`
)除了作为变量之外还有一个额外的缺陷,就是它会吃掉你的末尾换行符。
绕过限制
如果你想要使用变量,那么你必须通过编码来摆脱 NUL 字符,这里的其他各种解决方案都提供了聪明的方法来做到这一点(一个明显的方法是使用 base64 编码/解码)。
如果你关注内存或速度,你可能只想使用最小的解析器,并且只带引号 NUL 字符(和引号字符)。在这种情况下,这将对你有所帮助:
quote() { sed 's/\\/\\\\/g;s/\x0/\\x00/g'; }
然后,您可以通过将敏感数据输入quote
来确保在将其存储在变量和命令行参数中之前保护您的数据,这将输出一个不含NUL字符的安全数据流。 您可以使用echo -en "$var_quoted"
将原始字符串(包含NUL字符)返回,它将在标准输出上发送正确的字符串。
示例:
ascii_table() { echo -en "$(echo '\'0{0..3}{0..7}{0..7} | tr -d " ")"; }
myvar_quoted=$(ascii_table | quote)
echo -en "$myvar_quoted"
注意:使用| hd
可以以十六进制形式清晰地查看数据,并检查是否丢失了任何NUL字符。
更改工具
请记住,您可以在命令行中不使用变量或参数的情况下使用管道达到很远的效果,例如,请不要忘记<(command ...)
结构,它将创建一个命名管道(一种临时文件)。
编辑:quote
的第一个实现是不正确的,并且不会正确处理由echo -en
解释的\
特殊字符。感谢@xhienne发现这个问题。
编辑2:quote
的第二次实现存在bug,因为仅使用\0
,实际上会吃掉更多的零,因为\0
,\00
,\000
和\0000
是等价的。所以\0
被替换为\x00
。感谢@MatthijsSteen发现这个问题。
\0
,那是因为它是用来分隔变量结尾的字符。因此,存储 NUL 字符基本上就相当于将变量设置为空。 - Nick Bull