外壳脚本中的模式匹配效率



我有一个目录MAIN_DIR,其中包含 30 个子目录,每个子目录包含大约 30,000 个文件。我想遍历MAIN_DIR中的每个目录,并将与某种模式匹配的每 10 个文件复制到另一个位置。这是我的脚本:

cd /path/MAIN_DIR
num=0
for dir in *; do
     cd $dir
     for f in `find . -name *XYZ*`; do
          if [ `expr $num % 10` -eq 0 ]; then
              cp $f /new/location/new_dir/$f
          fi
          num=$((num+1))
     done
     cd ..
done

按预期工作,问题是它非常慢,大约需要 8 个小时才能运行所有 30 个目录。我知道模式匹配和模运算都相当慢,但 8 小时似乎有点高。我能做些什么来提高这个脚本的速度吗?

在我的机器上,每个包含 30,000 个文件的目录大约需要 1 分钟,而无需复制任何内容,而只需选择文件即可。所以我想你的 30+ 小时中大约有 8 分钟花在低效选择它们上,所以实际问题可能是复制。

您可以用这样的内容替换脚本来确定要复制的文件,但仍然需要 7+ 小时,除非您并行执行复制并且您的网络/驱动器可以提供该带宽。

find . -type f -name ... | awk '(FNR%10)==0'

对于所有 100 万个文件,这将在 24 秒内运行。

如果您使用的是ashdash,您可能无法改善这一点(我不确定)。

如果您使用的是 ksh 或 bash,请替换

if [ `expr $num % 10` -eq 0 ]; then

if (( $num % 10 )) ; then

这样,您将使用内置在 shell 中的内部评估,并避免创建子流程。

-- 此外,根据上面的评论,我包括这些示例评估来说明 % mod 运算符的使用:

 num=9;  if (( $num % 10 )) ; then echo not 10 ; else echo num%10 ; fi
    not a 10
 num=10 ;-if (( $num % 10 )) ; then echo not 10 ; else echo num%10 ; fi
    num%10
 num=20 ;-if (( $num % 10 )) ; then echo not 10 ; else echo num%10 ; fi
    num%10
 num=111;  if (( $num % 10 )) ; then echo not 10 ; else echo num%10 ; fi
    not a 10

我会(供我自己参考)time添加到cp cmd 的前面,即

time cp $f /new/location/new_dir/$f

以查看要复制的每个文件的单独成本。如果您通过慢速网络进行复制,或者从驱动器上的一个位置复制到同一驱动器上的另一个位置,则可能无法加快速度。

希斯

最新更新