0

膨大な量の出力を生成するプログラムを呼び出す bash スクリプトがあります。このデータの多くは、私が作成したことのない Python パッケージからのものであり、その出力は実際には制御できず、関心もありません。

その外部 Python パッケージによって生成された出力をフィルタリングし、「クリーンな」出力をログ ファイルにリダイレクトしようとしました。通常のパイプと grep 式を使用すると、多くの情報が失われました。これは、リダイレクト( 1および2 )で実際に発生する可能性があることを読みました。

それを修正するために、次のようなリダイレクトを作成しました。

#!/bin/bash
regexTxnFilterer="\[txn\.-[[:digit:]]+\]"
regexThreadPoolFilterer="\[paste\.httpserver\.ThreadPool\]"
bin/paster serve --reload --pid-file="/var/run/myServer//server.pid"  parts/etc/debug.ini 2>&1 < "/dev/null" | while IFS='' read -r thingy ; do
        if [[ ! "$thingy" =~ $regexTxnFilterer ]] && [[ ! "$thingy" =~ $regexThreadPoolFilterer ]]; then
                  echo "$thingy" >> "/var/log/myOutput.log" 
        fi
done

これにより、情報が失われることはなく (少なくとも私にはわかりません)、不要な文字列がフィルター処理されます (上記の 2 つの正規表現を使用)。

問題は、アプリケーション (bin/paster私が実行しているもの) が耐えられないほど遅くなったことです。同じ効果を達成する方法はありますが、パフォーマンスは向上しますか?

前もって感謝します!

更新 @ 2012-04-13 : shellterがこの質問へのコメントの 1 つで指摘したように、フィルタリングしたい出力の例を提供すると役立つ場合があります。ここにそれらの束があります:

2012-04-13 19:30:37,996 DEBUG [txn.-1220917568] new transaction
2012-04-13 19:30:37,997 DEBUG [txn.-1220917568] commit <zope.sqlalchemy.datamanager.SessionDataManager object at 0xbf4062c>
2012-04-13 19:30:37,997 DEBUG [txn.-1220917568] commit
Starting server in PID 18262.
2012-04-13 19:30:38,292 DEBUG [paste.httpserver.ThreadPool] Started new worker -1269716112: Initial worker pool
2012-04-13 19:33:08,158 DEBUG [txn.-1244144784] new transaction
2012-04-13 19:33:08,158 DEBUG [txn.-1244144784] commit
2012-04-13 19:32:06,980 DEBUG [paste.httpserver.ThreadPool] Added task (0 tasks queued)
2012-04-13 19:32:06,980 INFO [paste.httpserver.ThreadPool] kill_hung_threads status: 10 threads (0 working, 10 idle, 0 starting) ave time N/A, max time 0.00sec, killed 0 workers

ただし、ThreadPool に関連するメッセージは他にもいくつかありますが、キャッチできませんでした。

4

2 に答える 2

3

1 つには、行を追加するたびにログ ファイルを再度開いているということです。それはばかげている。

これの代わりに:

while ...; do
   echo "foo" >>filename
done

これを実行します(これにより、出力ファイルを新しい非標準出力ファイルハンドルで開き、標準出力に書き込みたい場合に明確な行が残るようになります):

exec 4>>filename
while ...; do
   echo "foo" >&4
done

ループ全体の stdout をリダイレクトすることもできます。

while ...; do
   echo "foo"
done >filename

...特に、これは単なる「エコー」行以外にも影響を与えるため、元のセマンティクスとはわずかに異なるセマンティクスになります。


または、いっそのこと -- Python ロギング モジュールを構成して、必要なものだけに出力をフィルター処理し、シェル スクリプトによる後処理をまったく気にしないようにします。

使用している Paste のバージョンが最新の Pyramid と十分に類似している場合は、これを ini ファイルに入れることができます (現在はparts/etc/debug.ini):

[logger_paste.httpserver.ThreadPool]
level = INFO

[logger_txn]
level = INFO

...そしてINFOレベル以下のもの (DEBUGメッセージを含む) は除外されます。

于 2012-04-16T22:50:22.393 に答える
1

これに対してgrepベースのソリューションを使用する方が速い場合があります

#!/bin/bash
regexTxnFilterer="\[txn\.-[[:digit:]]+\]"
regexThreadPoolFilterer="\[paste\.httpserver\.ThreadPool\]"
bin/paster serve --reload --pid-file="/var/run/myServer//server.pid"  parts/etc/debug.ini 2>&1 < "/dev/null" | grep -vf <(echo "$regexTxnFilterer"; echo "$regexThreadPoolFilterer") >> "/var/log/myOutput.log"

echo "$thingy" >> "/var/log/myOutput.log"行が実行されるたびにログファイルを開いたり閉じたりするため、ループが遅くなる可能性があります。grepの正規表現マッチングとbashのパフォーマンスに大きな違いがあるとは思いませんが、あったとしても驚かないでしょう。


後期編集

1行に1回出力を開閉することによって引き起こされるパフォーマンスの問題を修正する、はるかに簡単な方法があります。なぜこれが以前に私に起こらなかったのか、私にはわかりません。>>をループの外側に移動するだけです

#!/bin/bash
regexTxnFilterer="\[txn\.-[[:digit:]]+\]"
regexThreadPoolFilterer="\[paste\.httpserver\.ThreadPool\]"
bin/paster serve --reload --pid-file="/var/run/myServer//server.pid"  parts/etc/debug.ini 2>&1 < "/dev/null" | while IFS='' read -r thingy ; do
        if [[ ! "$thingy" =~ $regexTxnFilterer ]] && [[ ! "$thingy" =~ $regexThreadPoolFilterer ]]; then
                  echo "$thingy"
        fi
done  >> "/var/log/myOutput.log"

これがソリューションよりも速いか遅いかの説得力のある理由はわかりませんがgrep、元のコードにはるかに近く、暗号化が少し少なくなっています。

于 2012-04-13T23:12:24.060 に答える