簡體   English   中英

如何優化此bash功能?

[英]How to optimize this bash function?

我已經制作了一個bash函數,該函數可以將大於特定大小的圖像文件分開,但是我大約有20000個文件,這花費了太多時間,並且根本沒有占用太多CPU,所以我想知道是否有可能在沒有真正復雜的多重處理的情況下對其進行一點優化(我不介意多重處理,但我不想為如此簡單的任務編寫20行代碼)

這是我的代碼:

getpics() {
    dir="larger than $1x$2"
    mkdir "$dir"
    for f in `ls *`; do  
        a=`file "$f" | grep -Po ", \K[\d]*x[\d]*"`
        x=`grep -Po "\d*(?=x)" <<< "$a"`
        y=`grep -Po "x\K\d*" <<< "$a"`
        echo "$a _______________________ $x, $y"
        if [ $x -gt $1 ] && [ $y -gt $2 ] ; then
            mv "$f" "$dir/$f"
        fi  
    done
}

您可以嘗試盡可能避免調用外部工具,而使用bash內置函數。

例如,要替換所有grep ,可以使用bash ERE (在Bash 4+中有效):

re='^.* ([0-9]+)x([0-9]+),.*$'
for f in *; do
    desc=$(file "$f")
    if [[ $desc =~ $re ]]; then
        x=${BASH_REMATCH[1]}
        y=${BASH_REMATCH[2]}
        # ... check size & move
    fi
done
  1. 您不得解析ls輸出
  2. 您可以使用BASH正則表達式避免兩次grep調用(感謝下面的評論和@randomir的回答)

重構腳本:

re=', ([0-9]+)x([0-9]+)'
getpics() {
    dir="larger than $1x$2"
    mkdir "$dir"
    for f in *; do  
        if [[ $(file "$f") =~ $re ]]; then
           x=${BASH_REMATCH[1]}
           y=${BASH_REMATCH[2]}
           echo "$a _______________________ $x, $y"
           (( x > $1 && y > $2 )) && mv "$f" "$dir/$f"
        fi  
    done
}

首先讓我們做一些基准測試:

我們從if開始:

$ time for i in `seq 1 100000`; do if [ 2 -gt 1 ] && [ 3 -gt 2 ]; then a=1; fi; done

real    0m0.694s
user    0m0.693s
sys 0m0.003s

$ time for i in `seq 1 100000`; do if [[ 2 -gt 1 && 3 -gt 2 ]]; then a=1; fi; done

real    0m0.428s
user    0m0.424s
sys 0m0.006s

$ time for i in `seq 1 100000`; do if (( 2 > 1 && 3 > 2 )); then a=1; fi; done

real    0m0.366s
user    0m0.364s
sys 0m0.003s

$ time for i in `seq 1 100000`; do (( 2 > 1 && 3 > 2 )) && a=1; done

real    0m0.355s
user    0m0.352s
sys 0m0.005s

現在讓我們看看ls

$ time for i in `ls *`; do a=1; done

real    0m0.280s
user    0m0.249s
sys 0m0.036s

$ time for i in *; do a=1; done

real    0m0.128s
user    0m0.128s
sys 0m0.000s

現在有些人可能會懷疑

desc=$(file "$f")
if [[ $desc =~ $re ]]; then

會不同於

if [[ $(file "$f") =~ $re ]]; then

但是結果沒有區別。 我也測試了很多次,但是每次都比另一個隨機地快。 但我沒有將其結果放在這里,因為我認為它沒有用。

再次,您可能想知道之間是否存在差異

^.* ([0-9]+)x([0-9]+),.*$([0-9]+)x([0-9]+),

但是我測試了它,沒有。 但是根據regex101 ,最好的正則表達式(保留分組)是:

.*, ([0-9]+)x([0-9]*)     : 33 steps.
, ([0-9]+)x([0-9]+)       : 34 steps.
^.* ([0-9]+)x([0-9]+),.*$ : 38 steps.

現在讓我們比較獲取xy不同方法:

$ time (files=( * ); for f in "${files[@]:0:1000}"; do IFS=, a=(`file $f`);IFS=x b=(${a[8]});done;)

real    0m5.580s
user    0m1.147s
sys 0m4.498s

$ time (files=( * ); for f in "${files[@]:0:1000}"; do if [[ $(file "$f") =~ $re ]]; then x=${BASH_REMATCH[1]}; y=${BASH_REMATCH[2]}; fi; done)

real    0m5.817s
user    0m1.234s
sys 0m4.619s

$ time (files=( * ); for f in "${files[@]:0:1000}"; do a=(`convert $f -print "%w %h\n" /dev/null`);done;)

real    0m10.356s
user    0m3.624s
sys 0m6.793s

$ time (files=( * ); for f in "${files[@]:0:1000}"; do a=$(file "$f" | grep -Po ", \K\d+x\d+"); IFS=x read x y <<<"$a"; done;)

real    0m12.645s
user    0m2.235s
sys 0m13.914s

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM