为什么将 Base64 解码的字符串分配给变量时删除 0x00

Sil*_*lle 8 shell-script base64 xxd

我使用的是 Mac。在 Bash 中,我尝试解码 Base64 字符串,然后尝试打印十六进制值。我正在使用base64 -d命令,然后将其分配给变量。

myText='YYN29+2wV2XRAHymIyhgytWuqY4atgHnIUFfXA7FPOA='
myTextBytes=$(echo -n "$myText" | base64 --decode)
echo -n $myTextBytes | xxd -p -c 99999
Run Code Online (Sandbox Code Playgroud)

上述脚本的输出是:

618376f7edb05765d17ca6232860cad5aea98e1ab601e721415f5c0ec53ce0

但是,如果我直接运行以下命令:

echo -n "$myText" | base64 --decode | xxd -p -c 100000
Run Code Online (Sandbox Code Playgroud)

我得到:

618376f7edb05765d1 00 7ca6232860cad5aea98e1ab601e721415f5c0ec53ce0

我什至尝试使用openssl enc -base64并得到相同的结果。也就是说,00在分配给变量时被删除。00当我将它分配给变量时如何保留它?

Sot*_*oce 14

这不是两个 0x30 字符(ASCII“0”)的字符串中的“00”,而是一个 NUL 字符 0x00。如果将解码命令的输出通过管道传输到od -aor ,您可以看到这一点od -x

Bash 对命令替换(如var1=$( command ))的处理会去除 NUL/0x00 字符。然而,从 Bash 4.4 开始,它还会打印出警告。无法处理 NUL 字节是大多数 shell 的限制,zsh 是一个例外。但是,将参数中嵌入的 0x00 字符传递给 zsh 仍然受到影响的命令存在问题(因为这不是 zsh 中的问题,而是调用命令的 exec() 系列中的问题)。

如果你不想切换到 Perl、Python、Ruby 等其他语言,那么我建议尝试 zsh。

  • Base64 普遍使用的首要原因之一是通过非二进制安全路径传输和保护二进制数据。也许你最好的选择(假设你坚持使用bash)是将其保留为base64,直到你准备好使用它,然后解码它并在管道中使用它(如你的第二个命令中的工作)。 (17认同)
  • 至少(现代)bash 对这种情况给出了警告;dash 还可以进行剥离和 ksh93 截断。虽然可以编写 shell,以便在 shell 内部使用时 var 可以包含 NUL,例如 zsh,但 shell 变量通常(大部分?)用于作为参数和/或环境变量传递给您运行的程序 -并且执行此操作的操作系统调用被定义为使用由 NUL 终止(截断)的 C 语言字符串。 (4认同)
  • 请注意, `$(...)` 也会删除尾随换行符(0x0A 字节),因此即使在 zsh 中,您也必须解决它(使用通常的 `var=$(print -r - $encoded | base64 -d; 打印。); var=${var%.}`) (4认同)
  • zsh 在这里可以很好地处理 NUL,它们给出的命令直接工作并给出中间带有说明性“00”的输出。无需怀疑这一部分,尽管上面提到的其他警告确实适用。特别是,“echo $x”可以通过 zsh 的内置“echo”处理 NUL 字节,但“echo”的任何外部实现都不会也不能像这样工作。 (2认同)