bash内の正規表現

どういうわけか、スクリプトの速度を最適化することに従事しました。 このアルゴリズムはすでに強力でメインであり、並列化されており、すでに許容時間を超えて実行されています。 ときどき、コードの一部をなめる、外部コマンドを使用する場所をつかむ、組み込みのシェルコマンドとの調和をもたらす、ワーカーの停滞した役割に注目しました-sedストリームエディターは、私の急成長中のスクリプトでまだ正規表現を慎重に処理していました。

恐ろしい戦争sed vs awk vs grep vsでは、人々がお互いの喉をかじり、愛する編集者の名誉を守る場所がたくさんあります...

それでも、ほとんどの人は、外部コマンドの呼び出しを内部コマンドに置き換えることで、スクリプトの重要な場所を大幅に加速し、著者が笑顔になり、「処理が完了するまで」コーヒーを待つ時間が減ることを知っています。 これは、ある意味で、C言語を知っていて、Syでコードを書き直すことでプログラムを大幅に高速化できる場合、いくらか不十分です。 しかし、すぐにそれをクレイジーなものに書かないでください-いくつかのスクリプトはコード移植のために非常に膨大であり、さまざまなコマンドを使用して、exec()システムコールの厚かましい挿入からコードを膨張させます。

したがって、3番目のバージョンのbash開発者は、コマンド[[using =〜。

このbashの能力に関するGoogleの結果のほとんどは、「bash内で正規表現を使用する-Moveton」という同じ判断を下しています。

この記事では、すべてがどれほど悪いか(そして実際にはどういうわけか悪い)の判定に到達しようとします。



データ処理


いくつかの実験の後、私はまだ、CSV形式でブランド、モデル、およびそれらの修正に関するデータを含む車のデータベースを持っています。 ファイルは、テキスト形式の電子書籍のファンに十分な大きさで、約1 MBです。 想像力と選択範囲の発明の範囲を提供し、短いファイルよりも大きいファイルでの正規表現のパフォーマンスも評価できるようにします。

だから、私はブガッティを買うことにした庭師のフランクだとしましょう(このブランドの車はやや古いベースに4つしかないため、選択は彼女にかかっていました。さらに、どの庭師が混雑していないから苗木を残したくないのですか?バス、そして有名なブランド、魅力的な地元の美人から)。

使用されるデータベースでは、マシンはブランド別に並べ替えられています(ただし、テストの信頼性のために、並べ替えはモデル年ごとに行われました。テストで使用されたDBフラグメント:

"";" ";" (/)";" ( 100/)";" (^3)";" (../. )";" ( 100 )";" ";" ()";" ()";" ()";" ";" ";" ";" ()"

...

"Brilliance M3 1.8";"-";"210";"10.1";"1793";"170/5500";"7.7";"";"4488";"1812";"1385";"2008";"3";"4";"400"

"Bugatti Veyron EB 16.4";"43 968 000";"407";"3";"7993";"1001/6000";"24.1";"";"4465";"2000";"1205";"2006";"2";"2";"-"

"Bugatti EB 110 GT";"-";"340";"3.6";"3500";"559/8000";"14.3";"";"4400";"1960";"1125";"1991";"2";"2";"72"

"Bugatti EB 110 S";"-";"350";"3.4";"3500";"620/8000";"13.5";"";"4400";"1960";"1125";"1991";"2";"2";"72"

"Bugatti EB 112 6.0";"-";"300";"4.7";"5995";"461/6300";"18.2";"";"5070";"1960";"1405";"1993";"4";"4";"365"

"Buick Enclave CX";"-";"180";"-";"3564";"279/6600";"-";"";"5126";"2006";"1846";"2007";"5";"8";"535-3259"

...







この実験のタスクは、Bugattiブランドの組み込みbash正規表現を使用して文字列のサンプリング速度を評価することです。 怠け者は、これが1つのコマンドで正規表現なしで実行できることに気付くでしょう。

grep Bugatti auto.csv





しかし、状況はテストのために架空のものであり、実際の使用のためではありません-実際、ブガッティにとってはどの庭師で十分ですか?



試験方法


パフォーマンスの比較は、組み込みの正規表現を使用する関数と、sedストリームエディターを使用する関数のtimeコマンドの結果を比較することで構成されます。 (他のものを選択することは可能ですが、私は彼が好きです)。

簡略化するために、被験者は最初のパラメーターでファイルから既に読み取られたデータを受信し、tmpグローバル配列に結果を書き込みます。

したがって、sedエディターの機能を使用する関数は次のようになります。

function test_sed()

{

OLD_IFS=IFS

IFS=$'\n'

tmp=($(sed -n '/.*\(Bugatti[^\n]*\)/s//\1/p' <<< "$1"))

IFS=OLD_IFS

}






正規表現パターンは想像力の範囲を提供することに注意してください。行の始まりと終わりを示す文字を使用したり、まったく異なるパターンを考え出すこともできます。

私の機器の平均テスト結果は次のとおりです。

real 0m0.805s

user 0m0.719s

sys 0m0.082s







bashに組み込まれた正規表現は、システムコールに費やされる時間を大幅に削減し、全体のテスト時間をわずかに削減することが期待されています。



関数test_bash_rematch


bashで正規表現をテストする関数を書くのに時間がかかったので、私が遭遇した障害を説明する必要があります。

3番目のバージョンのbashでのテンプレート検索の一般的な形式は次のようになります。 [[ $str =~ "$regex" ]]





コマンドの結果は、パターンに一致する式が見つかった場合は0、見つからない場合は1、パターンが誤って書き込まれた場合は2です。 見つかったパターンとの一致は、S {BASH_REMATCH}配列に書き込まれます(インデックス0-パターン全体に一致する部分に対して、グループインデックスはパターンに現れる順序で)。

最初の障害に遭遇しました-あるバージョンから始めて、テンプレートを引用符で囲む必要はありません。これはman bashで見落としていました。

2番目の落とし穴-正規表現のためにPOSIXで使用され、貪欲で怠zyな定量化は機能しません。

最後に、ワールプールは、進行を大幅に遅くします-テンプレート内の検索結果は、テンプレートとの最初の一致または後続のもののいずれかになります(これは、最初に一致するまでファイルを行ごとに検索するストリームエディターではありません)。

その結果、次の2つの機能を使用してテストが実行されました。

function test_bash_rematch_single()

{

[[ "$1" =~ (Bugatti[[:alpha:][:digit:][:punct:][:blank:]]*) ]] && tmp[0]="${BASH_REMATCH[1]}"

}






1つのパターンマッチ、平均化されたテスト結果の検索:

real 0m0.678s

user 0m0.624s

sys 0m0.030s







sedよりも優れていますが、理解できます。これまでのところ、パターンマッチは1つしかありません。

そして、組み込みの読み取りコマンドとループを使用する2番目の関数:

function test_bash_rematch_while()

{

i=0

while read line

do

[[ "$line" =~ (Bugatti.*) ]] && tmp[i]="${BASH_REMATCH[1]}" && ((i++))

done <<< $1

}






結果とともに:

real 0m1.523s

user 0m1.360s

sys 0m0.030s









おわりに


結果からわかるように、bash正規表現を使用するときにシステムコールの処理に費やされる時間は本当に短縮されます。 ただし、現時点では、bashバージョン4.1.5(1)はテンプレートの検索を非常に遅くします。これにより、重要な場所で組み込みのbash正規表現が使用されなくなります。また、ランタイムが重要でない場合は、組み込みのbash正規表現も使用しないでください。これはシェル間の許容度を低下させるが、プラスを与えないためです。



PS


テンプレートを使用して再帰的に検索機能を実装することもできます。ソーステキストを2つの部分に分割するテンプレートを見つけると、テンプレートと一致する前後に、再帰によってそれらを自分自身に転送することができます(バックグラウンドに対して別々のスレッドで実行する場合)、これは動作しますより高速ですが、システム割り込みを処理する時間が増加し、ハンバーガーをen腸に変更します。



All Articles