2017-04-11 24 views
0

私はスクリプトをスピードアップしようとしていますが、現在は約30秒かかります。私はbashの初心者ですが、私はいくつかのヒントを見つけました(https://unix.stackexchange.com/a/169765でヒントを見つけましたが、まだ私の問題を修正できません)。grepとsedを使った遅いbashスクリプト

私がする必要があるのは、外部ファイルからデータを取得し、数値を2つの配列に抽出することです。私のスクリプトは遅すぎることを除いて、うまく動作します。

readData=`cat $myfile` 
# readData = [[1491476100000,60204],[1491476130000,59734],...,[1491476160000,60150]] 
# I have approximately 5000 points (two numbers in each point) 
pointTime=() 
pointVal=() 

for line in `echo $readData | grep -Po "[0-9]+,[0-9]+"`; do 
    # Get first number but drop last three zeroes (e.g. 1491476100) 
    pointTime+=(`echo $line | grep -Po "^[0-9]+" | sed "s/\(.*\)000$/\1/"`) 
    # Get second number, e.g. 60204 
    pointVal+=(`echo $line | grep -Po "[0-9]+$"`) 
done 

たぶん私はパラメータ展開内のいくつかの正規表現を使用することができますが、私は方法がわかりません。

+0

、我々はあなたが既にあなたは上記のコード内のコメントとして求めているものを見つけることができ、その後 – RavinderSingh13

+0

同じの詳細を助けることができる –

+1

何がデータをどうしようとしています一度あなたはそれが配列に読み込まれている? Bashはこのデータを処理するのに最適な選択肢になるとはっきりしていません。たとえば、入力ファイルが有効なJSONであることに注意してください。ほとんどの言語では、これをネイティブデータ構造にロードする簡単な方法があります。あるいは、JavaScriptで直接操作することもできます。 –

答えて

2

ファストここ

私はスクリプトを書くだろうかだオルタナティブ:

mapfile -t points < <(grep -Po '\d+,\d+' "$myfile") 
pointTime=("${points[@]%000,*}") 
pointVal=("${points[@]#*,}") 

またはファイルが整形式であることを確認していても

mapfile -t pointTime < <(grep -Po '\d+(?=000,)' "$myfile") 
mapfile -t pointVal < <(grep -Po ',\K\d+' "$myfile") 

。古いスクリプト

問題はすでに主な問題を識別:多くのプログラムは、ループ内で呼ばれているので、ループは、特に、遅いです。それにもかかわらず、ループを捨てることなくスクリプトを改善する方法についてのヒントがいくつかあります。いくつかの部分は、例えば

readData=`cat $myfile` 
`echo $readData | grep -Po "[0-9]+,[0-9]+"` 

grep -Po "[0-9]+,[0-9]+" "$myfile" 

echo $line | grep -Po "^[0-9]+" | sed "s/\(.*\)000$/\1/" 

のように書くことができ、不必要に複雑だった

grep -Po "^[0-9]+(?=000)" <<< "$line" 

大きな速度向上と同じように書き込むことができますbashの一致するoperを使用するgrepの代わりに、grepの代わりに=~を使用してください。

[[ "$line" =~ (.*)000,(.*) ]] 
pointTime+=("${BASH_REMATCH[1]}") 
pointTime+=("${BASH_REMATCH[2]}") 

+0

これは完全に説明的で便利です。私が実装した解決策は 'points =($(grep -Po '[0-9] +、[0-9] +' <<<" readData "))です。 pointTime =( "$ {points [@]%000、*}"); pointVal =( "$ {points [@]#*、}") '。実際のコードはもっと複雑なので、$ myfileは使用しませんでした。あなたのソリューションでは、コードは非常に速く、全く減速しません。 –

2

結果を配列に格納する必要があるのは疑いがあります。実際には、値をペアでループしたいと思うでしょう。いずれにしても、中間値をメモリに記憶することは、控えめで無駄である。

grep -Eo '[0-9]+,[0-9]+' "$myfile" | 
while IFS=, read -r first second, do 
    process value pair "${first%000}" "$second" 
done 

値を配列に格納することを強くお勧めする場合、ループの本体を変更する方法は明白です。あなたは私たちがINPUT_FILEと期待される出力をサンプリング示すことができた場合

pointTime+=("${first%000}") 
    pointVal+=("$second") 
+0

さらなる処理のためにすべてのデータを保存する必要があります。元の質問への私のコメントを参照してください。私がSocowiの答えを受け入れたとしても、あなたのソリューションは本当によく見えます。 +1 –

関連する問題