1

我想加密和解密大文件(想想 20m 行)的文本。我使用的加密服务最多只能加密 64kb。出于此问题的目的,假设我们坚持使用此服务。

我的解决方案是将大文件分成 64kb 的块,并行加密所有文件,然后将加密的部分放入tar.gz. 每个部分都有编号,part-xxx以确保我可以恢复原始文件。在解密时我解压缩,并行解密每个部分并按顺序连接结果。

有趣的部分:当我在足够大的文件上执行最后一部分时,会发生以下情况之一:

  1. tmux 会话终止,我被注销。没有日志,什么都没有。

  2. 我明白了:

/home/estergiadis/kms/decrypt.sh: line 45: /usr/bin/find: Argument list too long
/home/estergiadis/kms/decrypt.sh: line 46: /bin/rm: Argument list too long

我尝试了几种基于 xargs 的解决方案,但没有成功。这是有趣的代码:

echo "Decrypting chunks in parallel."
# -1 -f in ls helped me go from scenario 1 to scenario 2 above. 
# Makes sense since I don't need sorting at this stage.
ls -1 -f part-* | xargs -I % -P 32 bash -c "gcloud kms decrypt --ciphertext-file % --plaintext-file ${OUTPUT}.%"

# Best case scenario, we die here
find $OUTPUT.part-* | xargs cat > $OUTPUT
rm $OUTPUT.part-*

更有趣的是:当 find 和 rm 报告问题时,我可以转到包含所有部件的临时文件夹,自己运行完全相同的命令,一切正常。

万一这很重要,所有这些都发生在 RAM 挂载的文件系统中。但是 RAM 不可能是问题:我在一台 256GB RAM 的机器上,所涉及的文件占用 1-2GB 并且htop从未显示超过 10% 的使用率。

4

1 回答 1

2

你的问题在于这些:

ls -1 -f part-* | ...
find $OUTPUT.part-* | ...
rm $OUTPUT.part-*

如果你有太多的部分(part-*等),由 shell 完成的文件名扩展将导致一个带有太多参数的命令,或者你可能会超过最大命令长度。

find+xargs让你克服这个问题。您可以将任何使用 glob 列出当前目录中文件的命令替换为,例如:

find . -name GLOB -print -o ! -path . -prune | xargs CMD

-o ! -path . -prune告诉find不要进入子目录。xargs确保生成的命令行不超过最大参数或行限制。

所以对于这三行你可以做:

globwrap(){
    glob="$1"
    shift

    find . -name "$glob" -print -o ! -path . -prune |\
    sed 's/^..//' |\
    xargs "$@" # defaults to echo if no command given
}

globwrap 'part-*' | ...
globwrap "$OUTPUT"'.part-*' | ...
globwrap "$OUTPUT"'.part-*' rm

单引号可防止 shell 扩展我们传递给的 glob find

sed去掉./原本会附加到每个文件名的那些。

注意原来的lsfind前两种情况都不再需要了。

于 2020-02-21T05:09:59.913 回答