進行状況バーを含む出力をリアルタイムで grep するにはどうすればよいでしょうか?

進行状況バーを含む出力をリアルタイムで grep するにはどうすればよいでしょうか?

私はツール ( openocd) を使用していますが、大量のゴミを印刷し、次に基本的な進行状況バーがゆっくりと単純なドットを印刷し、その後再びゴミを印刷します。

この出力を でフィルタリングして、grep進行状況バーのある行のみをリアルタイムで表示します (つまり、 によって出力される各ドットがopenocdすぐにターミナルに印刷されます)。

openocd <args> |& grep '^\.'

問題は、grep行バッファリングされる (せいぜい) ため、完了するまで進行状況バーが表示されないことです。

ではどうすればよいですgrepか、またはこれを実現するための標準的な代替手段はありますか? 構成による方法があればopenocd便利ですが、より一般的なソリューションを希望します。

答え1

これは一種のハッキー/珍しい答えですが、実際には、これはあまりきれいではない方法で可能である可能性が高いということです。


grepそれ自体は改行文字に遭遇したときにのみ出力を印刷するようです。進行状況バーは更新時に改行文字を導入しない可能性が高いため、問題が発生します。

straceコマンドが呼び出しているシステム コールを表示するために使用されるツールです。これには、メモリ/ストレージへの読み取りや書き込み、ファイル記述子のオープン/クローズなどが含まれます。


を使用すると、プロセスがアクセスしているものを表示できます。パイプが に渡されるstrace場合、 を使用すると、に送られるテキストを表示できます。には、パイプされたコマンドからの出力が定期的に送信され、その出力をスニッフィングして表示できます。 でテストしていましたが、同様のシナリオに遭遇したようです。 は進行状況を表示するためにを使用するため、を使用しました。stoutgrepstracegrepstracersync --progressgrep##%rsync

rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%"

このコマンドを実行すると、strace出力は適切ではありませんが、私が使用したときは、通常は取得されないからstraceいくつかの が取得され、0%、21%、45%、68%、91%、100% の が表示され、約 1 秒ごとに更新されているように見えました (おそらく、進行状況の更新頻度に基づいています)。readrsyncgrepwritereadrsync

そのため、同じものを再度呼び出すと、あまり見栄えの良くない出力grepが得られます。stracegrep

rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%" 2>&1 > /dev/null | grep -o "[0-9]*%"

は に印刷される2>&1ため重要です。はにリダイレクトして、最初の の出力が報告されるのを防ぎます。この最終結果は次の出力でした。stracestderr> /dev/nullstdout/dev/nullgrep

0%
21%
45%
68%
91%
100%

を交換する必要がありますgrepが、うまくいくようです。見た目は良くありませんが、機能し、 の制限を回避しますgrepgrep -fのように機能する がtail -f便利そうです ( がすでに使用されていることは知っていますgrep -f)。

最初の目的は、一致する行のみがs呼び出しでリストされるため、実行されるテキストgrepをフィルタリングすることだけですが、テキストが移動するのを監視するための何かも必要です。stracereadstracereadstrace

答え2

最終的な答えは非常に複雑なので、Centimane の答えについて詳しく説明します。

すでにかなりハッキーでしたが、今では本当にひどいものになっています。

make flash \
    |& strace -e trace=read grep -e "^\." -e rror \
    |& stdbuf -o0 sed -ne 's/^.*"\.".*/\./p;/rror/p' \
    | stdbuf -o0 tr -d '\n' \
    ; echo

したがって、make flash上記は呼び出しですopenocd

strace上記で説明した Centimane のハックを使用しています。

sedread(0, ".", xxx)行を単一の.;に置き換えます。

trすべてを.1 行に保持し、最後のエコーで EOL のみを配置します。

それに加えて、sedと がtr呼び出されstdbuf -o0、stdout バッファ サイズが 0 に設定されます (EOL が削除されるため)。また、は、エラーの場合に何らかのゴミを出力するためにgrep/sedも使用されます。(e)rror

私はこの肥大化を最小限にしようと試みましたが、これ以上のことはできませんでした。

また、私は zsh/Ubuntu 14.04 を使用していますが、これが他の Unix でも動作するかどうかはわかりません。

関連情報