bash不能在变量中存储hexvalue 0x00


11

我正在尝试用dd做一些技巧。我认为可以在名为“ header”的变量中存储一些十六进制值,以将其通过管道传递给dd。

我没有变量的第一步是:

$ echo -ne "\x36\xc9\xda\x00\xb4" |dd of=hex
$ hd hex

00000000  36 c9 da 00 b4                                    |6....|
00000005

之后,我尝试了这个:

$ header=$(echo -ne "\x36\xc9\xda\x00\xb4") 
$ echo -n $header | hd

00000000  36 c9 da b4                                       |6...|
00000004

如您所见,我\x00$header变量中失去了价值。有人对此行为有解释吗?这真让我抓狂。


我懂了bash: warning: command substitution: ignored null byte in input
库萨兰达

您缺少引号应该是,header="$(echo -ne "\x36\xc9\xda\x00\xb4")"; echo -n "$header" | hd但这只会给出相同的结果。
ctrl-alt-delor

这可行header="\x36\xc9\xda\x00\xb4"; echo -n "$header" | hd,但与存储人类可读形式不同。
ctrl-alt-delor

Answers:


16

您不能在字符串中存储空字节,因为Bash使用C样式的字符串,该字符串将空字节保留给终止符。因此,您需要重写脚本以简单地通过管道传递包含空字节的序列,而Bash不需要将其存储在中间。例如,您可以这样做:

printf "\x36\xc9\xda\x00\xb4" | hd

顺便说一下,请注意,您不需要echo;您可以使用Bash printf来完成许多其他简单任务。

或者,可以使用一个临时文件来代替链接:

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence

当然,这具有文件/tmp/mysequence可能已经存在的问题。现在,您需要继续创建临时文件并将其路径保存在字符串中。

或者您可以通过使用流程替换来避免这种情况:

hd <(printf "\x36\xc9\xda\x00\xb4")

<(command)操作会在文件系统中的命名管道,将接收器的输出commandhd将收到的第一个参数,路径到管道,它会打开并阅读几乎像任何文件。您可以在这里了解更多信息:https : //unix.stackexchange.com/a/17117/136742


1
正确无误,但这只是实现细节,而不是确切原因。我看了一下,POSIX标准实际上需要这种行为,因此您有实际的理由。(正如某些人指出的那样,zsh它会这样做,但只能在nōn-POSIX模式下进行。)我实际上进行了研究,因为我想知道是否值得在mksh……中实现
mirabilos

@mirabilos,您是否愿意对此进行扩展?AFAICT,当输出具有NUL字符时,没有为POSIX指定行为来替换命令;对于POSIX模式下的zsh,我能想到的唯一相关的区别是在sh仿真中,\0默认值不是$IFSecho "$(printf 'a\0b')"sh.NET中仍然可以正常工作zsh
斯特凡Chazelas

3
@mirabilos考虑到shell比POSIX标准早了十年或更长时间,我您可能会发现,实际的实际原因是shell使用了C样式字符串,并且该标准是基于此构建的。
giusti

我找到了一个很好的Q,可以对printf和echo进行详细讨论。unix.stackexchange.com/questions/65803/…–
Paulb

8

您可以zsh改用这是唯一可以在其变量中存储NUL字符的外壳。这八字恰好是默认值$IFSzsh

nul=$'\0'

要么:

nul=$'\x0'

要么

nul=$'\u0000'

要么

nul=$(printf '\0')

但是请注意,您不能将这样的变量作为参数或环境变量传递给执行的命令,因为参数和环境变量是传递给execve()系统调用的NUL分隔的字符串(系统API的限制,而不是外壳程序的限制) )。但是zsh,您可以在中将NUL字节作为参数传递给函数或内置命令。

echo $'\0' # works
/bin/echo $'\0' # doesn't

1
“您可以改用zsh”。不用了,谢谢!我现在正在作为bash脚本初学者来教自己。我不想将自己与其他语法混淆。但非常感谢您提出建议
Frank

实际上,您zsh在问题中使用了语法。echo -n $header为是指到的内容传递$header变量作为最后一个参数echo -nzsh(或fishrces)语法,而不是bash 语法。在中bash,这具有非常不同的含义。更一般地讲zsh,就像kshbashGNU shell,或多或少是kshUnix de-facto shell 的部分克隆),但是Bourne shell的大多数设计特质是固定的(还有很多额外的功能,还有很多更加人性化/令人惊讶)。
斯特凡Chazelas

注意:zsh有时可能会更改为零字节:echo $(printf 'ab\0cd') | od -vAn -tx1c 打印`61 62 20 63 64 0a`,这是应该存在NUL的空间。
艾萨克(Isaac)

1
那是其他(无,无)shell无法复制的东西。这使得脚本在zsh中的行为非常特殊。我认为:zsh只是试图变得太聪明。
艾萨克(Isaac)

2
“修复”了POSIX sh标准中存在的设计失误,即习惯于编写zsh脚本意味着一个人已经习惯了如果在任何其他shell中进行练习都可能会带来麻烦的实践。这不是语法问题,它与另一种语言完全不同,以至于技能或习惯不太可能转移,但这不是当前情况。
查尔斯·达菲
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.