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

ill*_*ate 4 bash dash

我想shuf --zero-terminated用 here-document 对多行字符串执行。

Mic*_*mer 8

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

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


可以在 zsh 中做您想做的事情,这对 null 更加友好。

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

请注意,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
Run Code Online (Sandbox Code Playgroud)

这不一定完全等同于 here-document,因为这些文件通常由 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
Run Code Online (Sandbox Code Playgroud)

shuf默认情况下很高兴从标准输入中读取数据,因此按照我的理解,这应该适用于您的具体用例。如果您有更复杂的命令,位于管道的右侧可能会引入一些与作用域混淆的元素。


最后,您可以使用printf并使用它而不是 here-document将您的数据写入一个真实的文件。该选项已在另一个答案中介绍。您需要确保事后清理文件,并且mktemp如果存在任何实时安全问题,可能需要使用或类似(如果可用)来创建安全文件名。


ill*_*ate 6

谢谢你们。让我根据你们所有人发布一个答案,也许最适合我。

这个剧本很好地工作在bash和破折号,没有需要真正的文件或在bash进程替换,无需要额外的缓慢外部程序调用,即使你并不需要担心实体的任何逃生的问题,因为%sC的printf但你应该仍然要注意在你的 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)
Run Code Online (Sandbox Code Playgroud)

对于shuf只(不原意一般这里文档二选一):

shuf --echo "[tag1]
key1=value1
key2=value2
[/tag1]" "[tag2]
key3=value3
key4=value4
[/tag2]"
Run Code Online (Sandbox Code Playgroud)

  • 不要为此使用 `echo`,甚至不要使用 `/bin/echo`(例如,在 GNU 系统上,`/bin/echo` 是否支持 `-e` 取决于 `$POSIXLY_CORRECT` 是否在环境中,在许多其他系统上,`/bin/echo` 不支持 `-e` 或 `-n` 或 `\x00`)。使用 `printf '%s\0' '第一条记录' '第二条记录'... | 嘘...` (5认同)