2016-03-11 33 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秒。