长话短说:
问:如何保持计数器find -exec
循环?
我的用例:
我需要移动很多分散在各处的目录,所以我这样做了
find . -type d -name "prefix_*" \
-exec sh -c '
new_path="/new/path/$(basedir "$1")";
[ -d "$new_path" ] || mv "$1" "$new_path";
' find_sh {} \;
(真正的命令更复杂,因为我阅读了一些关于 的构成的元数据/new/path
。无论如何,我不想争论命令本身,它不是问题的一部分,只是用例)。
它工作得很好,但需要相当长的时间,我想跟踪进度。
所以我添加了一个计数器写入文件:
i=$(cat ~/find_increment || echo 0);
echo $((i+1)) | tee ~/find_increment;
这也很好用,但感觉就像真的进行大约 100.000 次磁盘读写操作是个坏主意。
我考虑过写入ramdisk
而不是磁盘,但在执行该任务所需的环境中没有该选项。
有没有更好的方法在运行之间保持计数器-exec
?
答案1
find
您可以find
与while read
循环或 GNU结合使用,而不是使用纯命令parallel
。两者都可能比 更快find
,-exec
因为您不需要为 找到的每个路径启动一个新的 shell find
。
使用 GNU Parallel 的解决方案
与GNUparallel
相比有以下优点while read
:
- 更容易获得正确的结果。不
IFS=
,也-r
需要。 - 内置作业编号变量
{#}
。
如需更方便的替换字符串,请查看教程。 - 如果需要,可以轻松并行化。
删除后-j1
,默认情况下您将拥有与核心一样多的工作线程。
script='
echo Processing job number {#}
new_path="/new/path/$(basedir {})"
[ -d "$new_path" ] || mv {} "$new_path"
'
find … -print0 | parallel -0 -j1 "$script"
被{}
替换为parallel
从 读取的正确引用的条目stdin
。请勿{}
再次引用。
parallel
使用启动该脚本的同一个 shell 执行该脚本。如果您开始parallel
使用bash
脚本bash
中的功能。
使用“边读边读”的解决方案
find … -print0 |
while IFS= read -r -d '' old_path; do
echo Processing job number "$((++job))"
new_path="/new/path/$(basedir "$old_path")"
[ -d "$new_path" ] || mv "$old_path" "$new_path"
done
答案2
如果可用,请将计数器存储在其中/dev/shm/
以防止磁盘写入。
=> 使用/dev/shm/find_increment
而不是~/find_increment
.