【问题标题】:Running a command over too many files对太多文件运行命令
【发布时间】:2020-02-20 15:35:12
【问题描述】:

我想加密和解密大文件(想想 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% 的使用率。

【问题讨论】:

  • 您有一台安装了 256GB RAM 的机器,但您将未加密的数据以 64kB 块的形式通过 Internet 发送出去以对其进行加密?
  • 加密和解密都发生在具有 256GB RAM 的同一台机器上。不会通过 Internet 发送任何内容。
  • 不确定我是否明白这一点,但您的find 命令是错误的。你想要find . -name "$OUTPUT.part-*" ...
  • ... 而不是find ... | xargs... 你可能想要find ... -exec cat {} \; > somewhere
  • xargscat 具有相同的限制,请参阅sysctl -a | grep -i argmax

标签: encryption xargs concurrent-processing


【解决方案1】:

你的问题在于这些:

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 扩展我们传递给 find 的 glob。

sed 去掉了./,否则会在每个文件名之前添加。

请注意,前两种情况不再需要原来的lsfind

【讨论】:

    猜你喜欢
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多