web-dev-qa-db-ja.com

"tail -f | grep error" with while loop is not working

以下のコマンドは結果を与えていません。ファイルのエラー行をgrepしてテーブルに挿入したい。

機能していないコマンド:

tail -f logfile.log | grep  ERROR|while read msg; do psql -d testdb -c insert into t values('$msg'); done

しかし、grep ERRORコマンドからのコード、期待どおりに動作しています。何が起こっているのかわかりませんか?

正常に動作しているコマンド:

tail -f logfile.log|while read msg; do psql -d testdb -c insert into t values('$msg'); done

ファイルには以下のデータがあると想定できます。

ERROR
sql committed
ERROR
ERROR
error
...
3
ram

2つのこと:

  1. 質問で記述されているように、コードはリテラル文字列$msgを挿入します(機能する場合)。代わりに二重引用符を使用してください。ここでは、ステートメント全体を二重引用符で囲み、$msgを展開します。シェルコードは、grepからの結果に応じて、依然として脆弱です。 $msgの文字列は、単一の'または他の特殊文字がステートメントを壊さないように、適切にサニタイズするのが理想的です(または、さらに悪いことに ユーザーからのコメントcas以下 )。

    tail -f logfile.log |
    grep -F 'ERROR' |
    while read msg; do
        psql -d testdb -c "insert into t values('$msg')"
    done
    

    また、固定文字列を使用して検索しているため、-Fgrep呼び出しに追加しました(これは、主にドキュメント化の目的で)。

  2. grepは出力をバッファリングするため、出力バッファがいっぱいになるまで何も生成しません。これは実際には「機能しない」という印象を与えますが、grepが出力バッファーをフラッシュして、十分なデータが入るまでは何もしません。これはパフォーマンスの最適化です。

    GNU grep(およびOpenBSDなどの同じユーティリティの他のいくつかの実装)は、--line-bufferedオプションを使用してラインバッファリングすることができます。

    tail -f logfile.log |
    grep --line-buffered -F 'ERROR' |
    while read msg; do
        psql -d testdb -c "insert into t values('$msg')"
    done
    

注:現在PostgreSQL(?)インスタンスを実行していないため、これはテストしていません。

6
Kusalananda