while ループが動作しない "tail -f | grep error"

while ループが動作しない "tail -f | grep error"

次のコマンドは結果を提供しませんでした。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
...

答え1

2つ:

  1. 質問で書かれたように$msg一重引用符を使用したため、コードはリテラル文字列(有効な場合)を挿入します。代わりに二重引用符を使用してください。ここでは、文全体を二重引用符で囲みました。これにより内部が拡張されます$msg。シェルコードはまだ脆弱です。理想的には、単一または他の特殊文字によって文が破損しないように(またはより悪い場合は参照)、grep文字列を適切に削除する必要があります。$msg'ユーザーの意見カス次のような)。

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

    また、固定文字列を使用して検索するときに呼び出しを追加しました-F(主に文書化目的です)。grep

  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(?)インスタンスが実行されていないため、まだテストしていません。

関連情報