我想加密和解密大文件(想像20m行)的文本。我使用的加密服务最多只能加密64kb。出于这个问题的目的,假设我们坚持使用此服务。
我的解决方案是将巨大的文件分割为64kb的块,对所有文件进行并行加密,然后将加密的部分放入tar.gz
。每个部分都编号为part-xxx
,以确保我可以恢复原始文件。在解密时,我解压缩,并行解密每个部分并按顺序合并结果。
有趣的部分:当我在足够大的文件上执行最后一部分时,发生以下情况之一:
tmux会话终止,我退出了。没有日志,什么都没有。
我明白了:
/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报告问题时,我可以进入temp文件夹,包括所有部分,自己运行完全相同的命令,一切正常。
如果很重要,所有这些都发生在安装有RAM的文件系统中。但是,RAM可能不是问题:我在具有256GB RAM的计算机上,所涉及的文件占用1-2GB,htop
的使用率从未超过10%。
您的问题是这些:
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
单引号可防止外壳扩展我们试图传递给find
的glob。
[sed
删除要附加到每个文件名的./
。
请注意,前两种情况不再需要原始的ls
和find
。