ファイルを監視したい。そのため、1行に1つのスクリプトを実行するために、次のコマンドを使用してファイルを追跡しました。
tail -3f logfile.log | grep "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh
しかし、スクリプトが実行されていないようです。grep
次のパイプには入力がないことがわかりました。
私が試したとき、
tail -3f logfile.log | grep "action.*add"
効率的。ただし、次のフィルタ(例:sed
など)が与えられると、以下のようには機能しません。grep
xargs
tail -3f /var/tmp/rabbitmq-tracing/logfile.log | grep "action.*add" | grep add
これが起こる理由とこの問題を克服する方法を理解するのに役立ちます。
編集1: デフォルトでは、次の作業が機能しなければなりませんでした。なぜ今はうまくいかないのか混乱しています。
tail -f file.txt | grep something | grep something | grep something
編集2: 最初のgrep以降の出力行は、以下のようにjson文字列になります。この行をbashスクリプトへの入力として使用したいと思います(一重引用符で囲みます)。
{"twNotif": {"originator": "api", "chain": "test", "txId": "08640-0050568a5514", "version": "1.0", "msgType": "api", "twData": {"api": {"hostId": "007bdcc5", "user": "test", "cmdTxt": "100599"}}, "action": "add", "store": "test", "msgTime": 1467280648.971042}}
答え1
--line-buffered
スイッチの使用grep
tail -3f logfile.log | grep --line-buffered "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh
男のgrepから:
--line-buffered 出力にラインバッファリングを使用します。これによりパフォーマンスが低下する可能性があります。
またはあなたは使用することができますstdbuf
もっと読む
stdbufを使用すると、プログラムに関連する3つの標準I / Oストリームのバッファリング操作を変更できます。要約:
次の構文を使用してください。
... | stdbuf -oL grep ... | ...
あなたの例:
tail -3f logfile.log | stdbuf -oL grep "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh
答え2
他の人が指摘したように、grep
ラインバッファリングが問題の明らかな原因です。
ただし、現在実行中の作業にはあまり明確ではありませんが、他の問題もあります。
sed
まず、に入力できるように、各出力行の先頭と末尾にアポストロフィを追加するようですxargs
。これは必要ありません。オプションをxargs
使用して、-d
区切り文字で改行を使用するように指示できます。入力ラインがないときに何もしないようにすることです)xargs -d'\n' -r
-r
xargs
次に、正規表現を使用してjsonデータを解析します。正規表現を使用したXMLまたはHTMLの解析により、複雑でネストされた構造を処理することは信頼できず、非常に困難または不可能で壊れやすく、突然の衝突が発生しやすいです。 XMLまたはHTMLを解析しません。正規表現の使用。それ動作しません。 JSONにも同様に適用されます。。
代わりに、またはjsonデータからフィールドを抽出するなどjq
のものを使用する必要があります。jsonpipe
たとえば、
jq -c 'select(.twNotif.action == "add")' file.txt |
xargs -d'\n' -r -L 1 -P 5 ./testscript.sh
ただパイプしたいなら作業フィールド値xargs
(二重引用符なし)次のことができます。
jq 'select(.twNotif.action == "add") | .twNotif.action' file.txt |
sed -e 's/"//g' |
xargs -d'\n' -r -L 1 -P 5 ./testscript.sh
次の作業に使用するのはjsonpipe
簡単です。awk
jsonpipe < file.txt |
awk '$1 == "/twNotif/action" {gsub(/"/,""); print $2}' |
xargs -d'\n' -r -L 1 -P 5 ./testscript.sh
(ここのリダイレクトはとは異なり、jq
stdinjsonpipe
でのみ機能します。)
ところで、jsonデータを、、jsonpipe
などの行ベースのツールで使用するのに適した行ベースの形式に変換します。例えば:sed
grep
awk
$ jsonpipe < file.txt
/ {}
/twNotif {}
/twNotif/originator "api"
/twNotif/chain "test"
/twNotif/txId "08640-0050568a5514"
/twNotif/version "1.0"
/twNotif/msgType "api"
/twNotif/twData {}
/twNotif/twData/api {}
/twNotif/twData/api/hostId "007bdcc5"
/twNotif/twData/api/user "test"
/twNotif/twData/api/cmdTxt "100599"
/twNotif/action "add"
/twNotif/store "test"
/twNotif/msgTime 1467280648.971042
jq
特にjson形式の出力が不要な場合は、より使いやすくなります。
たとえば、次のように簡単に使用できますjq
。
$ jsonpipe <file.txt | awk '{gsub(/\//,"."); print $1}'
.
.twNotif
.twNotif.originator
.twNotif.chain
.twNotif.txId
.twNotif.version
.twNotif.msgType
.twNotif.twData
.twNotif.twData.api
.twNotif.twData.api.hostId
.twNotif.twData.api.user
.twNotif.twData.api.cmdTxt
.twNotif.action
.twNotif.store
.twNotif.msgTime
答え3
あなたが見ている問題はおそらく「パイプバッファリング」です。パイプ内のさまざまなコンポーネントの出力は(あなたの場合grep
)もはやラインバッファリングではなくブロックバッファリングであり、バッファはおそらく次のコンポーネントではなく4Kです。すぐにデータを参照してください。それ〜するデータが十分に入ってきたら見てください...
解決策は少し痛いです。幸いexpect
、パッケージには役立つコマンドが付属していますunbuffer
。 man unbuffer
使用方法の詳細です。
これは、パイプラインのコンポーネントが端末と通信していると考えさせ、ラインをバッファリングされたままにすることによって機能します。