我想使用parallel
或使用其他工具或方法将许多目录并行拆分为子目录。
例如,我有 1 000 000 个包含内容的目录,但对于一个目录来说太多了,所以我想在主目录中创建 10 个目录,并在每个目录中移动 100 000 个原始目录。我还想使用按日期排序。我已经问过了类似的问题在这里,但这并不重复,因为我尝试了新命令,得到了新结果,现在我重新提出了问题。
所以,我已经尝试过这个
ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}"
和这个
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
命令,但它只将 ~10 000 移动到一个子目录中(有时 ~6200,有时 ~12 500)并创建太多子目录 - 有时比我需要的多 10 倍。
我也尝试使用这个:
ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
但它给了bash: /bin/ls: Argument list too long
。
当然,我不需要每个子目录中正好有100 000个目录,它可以是101 000或98 500个目录,它应该是100 000范围内的数字
我如何并行或使用执行此任务parallel
?
答案1
问题是 shell 扩展后命令行可以占用的字节数有上限,这个限制取决于系统的限制
getconf ARG_MAX
mv {}
因此,只要达到最大限制,参数的数量就会根据输入文件名的长度而变化。
避免这种限制同时不放弃使用并行的解决方案是将任务分为两个阶段
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
说明
第一阶段使用选项
--pipe
将标准输入拆分为确定数量的较小的标准输入,每行包含选项指定的 n 行-N
。您可以使用此示例观察效果seq 1000000 | parallel -N 100000 --pipe wc -l
给出了 100000 处的精确分割
100000 100000 100000 ...
在第二阶段,内部平行采取较小的标准输入作为执行作业的新标准输入,该
-X
选项会插入命令行长度允许的尽可能多的参数mkdir dir_{#}; parallel -X mv -t dir_{#}
答案2
这个问题涉及大量IO。我怀疑这parallel
在这种情况下是否真的有用。
无论如何,我建议您考虑“传统”方法:
mkdir dir_{1..10}
ls -tr | nl | \
awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'
在哪里
ls -tr | nl
按日期对目录进行排序并添加辅助目录号$2 !~ /^dir_/
用于跳过刚刚创建的文件夹。i=1+int($1/100000)
根据目录号计算文件夹的编号print $2 | "xargs mv -t dir_"i
移动时无需进程扩散
如果可能的话,也比较各自的时间:(time ....
并与我们分享结果☺)