illiterate Asked: 2019-03-01 20:38:49 +0800 CST2019-03-01 20:38:49 +0800 CST 2019-03-01 20:38:49 +0800 CST 如何在此处文档中转义空字符?(bash 和/或破折号) 772 我想shuf --zero-terminated用 here-document 处理多行字符串。 bash dash 3 个回答 Voted Best Answer Michael Homer 2019-03-01T22:29:37+08:002019-03-01T22:29:37+08:00 Bash 和 dash 中的 Here-documents 不支持这一点。您不能将 null 存储在变量中,它们会从命令替换中删除,您不能按字面意思写一个,也不能在 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 请注意,尽管 heredocs 有一个隐式终止换行符,这可能是不可取的(它将是shuf最终 null 之后的额外字段)。 对于 Bash,您可以使用几乎等同于您的 heredoc 的进程替换printf与内联或echo -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 这不一定完全等同于 here-document,因为它们通常由 shell 秘密地放入真实文件中(这对于可查找性等很重要)。 由于您可能想要禁止终止换行符,因此您甚至不能在内部的命令中使用heredoc - 它必须printf/echo -ne如果安全才能对输出进行细粒度控制。 您不能在破折号中进行进程替换,但在任何 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最后,您可以使用并使用它而不是 here-document将数据写入真实文件。该选项已包含在另一个答案中。您需要确保之后清理文件,并且mktemp如果有任何实时安全问题,可能需要使用或类似的工具来创建安全的文件名。 illiterate 2019-03-02T00:14:12+08:002019-03-02T00:14:12+08:00 谢谢你们。让我根据你们所有人发布一个答案,也许对我最好。 该脚本在 bash 和 dash 中运行良好,不需要在 bash 中进行真正的文件或进程替换,不需要额外缓慢的外部程序调用,即使您不需要担心实体中%s的任何转义问题,如C printf,但您应该仍然注意在您的外壳本身中进行字符串转义。 #!/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]" fpmurphy 2019-03-01T21:18:51+08:002019-03-01T21:18:51+08:00 我不认为你可以在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 $
Bash 和 dash 中的 Here-documents 不支持这一点。您不能将 null 存储在变量中,它们会从命令替换中删除,您不能按字面意思写一个,也不能在 here-document 中使用 ANSI-C 引用。这两个 shell 都不是空友好的,如果确实进入,它们通常被视为(C 样式)字符串终止符。
您有几个选择:使用真实文件、使用 zsh、使用进程替换或使用标准输入。
你可以在 zsh 中做你想做的事,这对 null 更友好。
请注意,尽管 heredocs 有一个隐式终止换行符,这可能是不可取的(它将是
shuf
最终 null 之后的额外字段)。对于 Bash,您可以使用几乎等同于您的 heredoc 的进程替换
printf
与内联或echo -e
创建空值:这不一定完全等同于 here-document,因为它们通常由 shell 秘密地放入真实文件中(这对于可查找性等很重要)。
由于您可能想要禁止终止换行符,因此您甚至不能在内部的命令中使用heredoc - 它必须
printf
/echo -ne
如果安全才能对输出进行细粒度控制。您不能在破折号中进行进程替换,但在任何 shell 中,您都可以从子 shell 中输入标准输入:
shuf
默认情况下很高兴从标准输入中读取,因此据我了解,这应该适用于您的具体用例。如果您有一个更复杂的命令,则位于管道的右侧可能会引入一些与范围界定混淆的元素。printf
最后,您可以使用并使用它而不是 here-document将数据写入真实文件。该选项已包含在另一个答案中。您需要确保之后清理文件,并且mktemp
如果有任何实时安全问题,可能需要使用或类似的工具来创建安全的文件名。谢谢你们。让我根据你们所有人发布一个答案,也许对我最好。
该脚本在 bash 和 dash 中运行良好,不需要在 bash 中进行真正的文件或进程替换,不需要额外缓慢的外部程序调用,即使您不需要担心实体中
%s
的任何转义问题,如C printf,但您应该仍然注意在您的外壳本身中进行字符串转义。仅用于
shuf
(不打算使用一般的此处文档替代方案):我不认为你可以在heredoc中做你想做的事。但是,使用
echo
如下示例所示是微不足道的: