如何转义此处文档中的空字符?(bash 和/或破折号)

如何转义此处文档中的空字符?(bash 和/或破折号)

我想shuf --zero-terminated使用此处文档对多行字符串执行操作。

答案1

Bash 和 dash 中的 Here-documents 不支持这一点。您不能在变量中存储 null,它们会从命令替换中删除,您不能按字面意思编写 null,并且不能在此处文档中使用 ANSI-C 引用。这两个 shell 都不是 null 友好的,如果进入的话,它们通常被视为(C 风格)字符串终止符。

您有几个选择:使用真实文件、使用 zsh、使用进程替换或使用标准输入。


在 zsh 中完全按照您想要的方式进行操作,这对空值更加友好。

zsh% null=$(printf '\x00')
zsh% hexdump -C <<EOT
heredoc> a${null}b${null}
heredoc> EOT
00000000  61 00 62 00 0a                                    |a.b..|
00000005

请注意,尽管heredocs有一个隐式的终止换行符,这可能并不理想(它将是shuf最终空值之后的额外字段)。


对于 Bash,您可以使用流程替代几乎等同于您的heredoc结合printfecho -e创建内联空值:

bash$ hexdump -C < <(
printf 'item 1\x00item\n2\x00'
)
00000000  69 74 65 6d 20 31 00 69  74 65 6d 0a 32 00        |item 1.item.2.|
0000000e

这不一定完全等同于此处文档,因为这些文件通常由 shell 秘密放入真实文件中(这对于可查找性等很重要)。

由于您可能想抑制终止换行符,因此您甚至不能在命令内部使用heredoc - 它必须是printf/echo -ne如果安全才能对输出进行细粒度控制。


您无法在 dash 中进行进程替换,但在任何 shell 中,您可以从子 shell 中通过管道输入标准输入:

dash$ (
printf 'item 1\x00'
printf 'item\n2\x00'
) | hexdump -C
00000000  69 74 65 6d 20 31 00 69  74 65 6d 0a 32 00        |item 1.item.2.|
0000000e

shuf默认情况下很乐意从标准输入中读取内容,因此据我了解,这应该适用于您的具体用例。如果您有更复杂的命令,则位于管道的右侧可能会引入一些与范围界定混淆的元素。


最后,您可以使用该文件将数据写入真实文件printf,而不是使用此处文档。该选项已包含在另一个答案。您需要确保事后清理文件,并且可能想要使用mktemp或类似的内容(如果存在任何实时安全问题)可用于创建安全文件名。

答案2

谢谢你们。让我发布一个基于你们所有人的答案,也许对我来说是最好的。

该脚本在 bash 和 dash 中运行良好,不需要真实文件或bash 中的进程替换,不需要额外缓慢的外部程序调用,甚至您不需要担心实体中的任何转义问题,%s打印输出,但你仍然应该注意 shell 本身的字符串转义

#!/bin/sh
printf '%s\0' "[tag1]
key1=value1
key2=value2
[/tag1]
" "[tag2]
key3=value3
key4=value4
[/tag2]
" | shuf --zero-terminated
#also see man printf(1)

为了shuf仅(无意于一般此处文档的替代方案):

shuf --echo "[tag1]
key1=value1
key2=value2
[/tag1]" "[tag2]
key3=value3
key4=value4
[/tag2]"

答案3

我认为你不能在heredoc中做你想做的事。然而,使用起来很简单echo,如下例所示:

$ cat demo
#!/bin/bash

echo -ne "one\0" > outfile
echo -ne "two\0" >> outfile
echo -ne "three\0" >> outfile

$ ./demo
$ od -a outfile
0000000   o   n   e nul   t   w   o nul   t   h   r   e   e nul
0000016
$ 

答案4

我最终使用了一个“技巧”

cat <<EOS | cat - <(echo -e "\0") | most
{
  "version":"1.1",
  "gelf-toekn":"SOMETHIN",
  "host": "api.ivsdev.net",
  "short_message": "foo",
   "full_message": "bar",
   "level": 1
}
EOS

第一个定界符猫通过管道输送到第二个定界符猫中,第二个定界符猫将其与空字节连接起来。

相关内容