bash 无法将十六进制值 0x00 存储在变量中

Fra*_*ank 13 linux bash dd shell-script

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

我没有变量的第一步是这样的:

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

00000000  36 c9 da 00 b4                                    |6....|
00000005
Run Code Online (Sandbox Code Playgroud)

之后我尝试了这个:

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

00000000  36 c9 da b4                                       |6...|
00000004
Run Code Online (Sandbox Code Playgroud)

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

giu*_*sti 18

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

printf "\x36\xc9\xda\x00\xb4" | hd
Run Code Online (Sandbox Code Playgroud)

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

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

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence
Run Code Online (Sandbox Code Playgroud)

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

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

hd <(printf "\x36\xc9\xda\x00\xb4")
Run Code Online (Sandbox Code Playgroud)

<(command)操作会在文件系统中的命名管道,将接收器的输出commandhd将接收该管道的路径作为它的第一个参数——它将几乎像任何文件一样打开和读取该管道。您可以在此处阅读更多相关信息:https : //unix.stackexchange.com/a/17117/136742

  • @mirabilos 考虑到 shell 比 POSIX 标准早十年或更长时间,我*猜*你会发现实际的*实际*原因是 shell 使用 C 风格的字符串,而标准是围绕它构建的。 (4认同)

Sté*_*las 9

您可以zsh改用 which 是唯一可以在其变量中存储 NUL 字符的 shell。该字符甚至恰好在 in 的默认值$IFSzsh

nul=$'\0'
Run Code Online (Sandbox Code Playgroud)

或者:

nul=$'\x0'
Run Code Online (Sandbox Code Playgroud)

或者

nul=$'\u0000'
Run Code Online (Sandbox Code Playgroud)

或者

nul=$(printf '\0')
Run Code Online (Sandbox Code Playgroud)

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

echo $'\0' # works
/bin/echo $'\0' # doesn't
Run Code Online (Sandbox Code Playgroud)

  • 已经“修复”了 POSIX sh 标准中存在的设计错误,习惯于编写 zsh 脚本意味着人们正在习惯于在任何其他 shell 中进行练习时会出现错误的实践。对于与不同语言如此不同以至于技能或习惯不太可能转移的语法来说,这不是问题,但目前的情况并非如此。 (2认同)