2016-03-11 32 views
0

我有一个包含30个子目录的MAIN_DIR目录,每个子目录包含大约30,000个文件。我想浏览MAIN_DIR中的每个目录,并将每个匹配特定模式的第10个文件复制到另一个位置。这是我的脚本:shell脚本中的模式匹配效率

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小时似乎有点高。有什么我可以做的,以提高这个脚本的速度?

+1

很多事情,但有没有使用'expr'(这需要一个子shell和是非标准的,基本上过时)开始,只是使用shell算术'$((NUM%10))。如果你正在检查'== 0'并且只使用'if!',你也可以避免使用'\ ['/'test'' ((num%10));然后'(也是shell算术),因为手册页说“如果表达式的值不为零,返回状态为0;否则返回状态为1”。这就是说我认为这个问题比代码更适合[Code Review](https://codereview.stackexchange.com/)。 –

+1

另外[不要用'for for'读取行](http://mywiki.wooledge.org/DontReadLinesWithFor)。 –

+2

我投票结束这个问题作为题外话,因为它似乎更适合于https://codereview.stackexchange.com/比这里作为代码的作品。 –

回答

0

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

如果您正在使用KSH或bash,与

if (($num % 10)) ; then 

更换

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

这样,你会使用内置到壳体内部评估,避免创建子进程。

- 此外,基于上述的意见,包括我说明如何使用% 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 

看到每个文件的个别成本被复制。如果您正在通过慢速网络进行复制,或者在同一个驱动器上从一个驱动器上的另一个位置复制到另一个位置,则可能没有太多的工作可以加快速度。

IHTH

+0

'(('不是POSIX,但是'如果test'$(($ num%10))-eq 0'在没有调用任何子壳或子进程的情况下可以工作 – chepner

+0

@chepner:Arg,更多POSIXisms !--)。好吧,很好知道,如果OP需要符合POSIX,那么'if test ..'是正确的答案。但是你是否在说'if((..))'确实调用了一个子shell?它是我的理解(在至少对于ksh来说)处理是在shell的内部,感谢评论,祝大家好运 – shellter

+0

不,'((...))'很好;作为内置的算术*语句*,它确实为了符合POSIX标准,你需要将算术表达式*'$((...))'嵌入到另一个命令中以达到相同的效果(尽管从技术上讲,POSIX中没有任何东西需要'test'作为内置的命令,只是可用的,但你可以做的事情不多。) – chepner

1

你的脚本需要每在我的机器30,000文件目录1分钟左右 - 不复制任何东西,但只是选择的文件。所以我想你的8个小时的30分钟左右花费在低效率的选择上,所以实际的问题可能是复制。

你可以像这样的东西来确定要复制的文件替换你的剧本,但它仍然会采取7+小时,除非你做的复制在并行和网络/驱动器可以提供的带宽。

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

对所有100万个文件运行24秒。