find -exec 并增加计数器/进度

find -exec 并增加计数器/进度

长话短说:

问:如何保持计数器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您可以findwhile 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.

相关内容