
いくつかのアプリケーションステータスを出力するコマンドがあるとします。このコマンドは永久に(またはCCまで)実行され、アプリケーション内で何かが発生した場合は1行を出力します。次の形式で出力されます。
State N: Stuff M happened
collapse_prog
私は私が提供する正規表現に基づいてコマンド出力行を取得し、以前の状態を上書きするプログラムが欲しいです。たとえば、入力正規表現がState(\ d +)であるとし、次のコマンドを実行します。
my_command | collapse_prog
そしてmy_command
出力
State 1: Stuff A happened
State 2: Stuff B happened
その後、collapse_prog
そのまま表示する必要がありますが、my_command
別の行を出力した後
State 1: Stuff C happened
これにより、collapse_prog
次のような出力が出なければなりません。
State 1: Stuff C happened
State 2: Stuff B happened
すでにそのようなプログラムがありますか?
答え1
非常に基本的なソリューションTxR不明な言葉:
$ program | txr stcoll.tl
どこstcoll.tl
:
(let ((states (hash)))
(whilet ((line (get-line)))
(when-match `State @s: @status` line
(set [states s] status)
(dohash (s status states)
(put-line `State @s: @status`))
(put-string `\e[@(len states)A`)
(flush-stream *stdout*))))
どのように機能するかは、各週の最新の状態がメインIDに基づいてハッシュテーブルに格納されることです。ステータス行を取得するたびにハッシュを更新してから印刷します。印刷後、ESC[<n>A
VT100 / ANSIエスケープシーケンスを使用してカーソルをその行だけ後ろに移動します。これは、端末ウィンドウが全ての状態に対して十分に高いと仮定する。これは非常にシンプルなインタラクティブビューツールに適しています。
より複雑なプログラムは、タイムアウト(例:1秒)後に標準入力をポーリングします。または設定可能です。次に、入力ループを通過するたびに行が受信されているかタイムアウトしているかにかかわらず、ハッシュが変更されたことを確認し、変更された場合は、最後の更新以降に更新サイクルが期限切れになったかどうかを確認します。この場合は、ディスプレイを更新してください。
これらのプログラムは、入力がすぐに到着するとディスプレイをより効率的に更新します。
ここにいる:
(let* ((states (hash))
(last-time 0)
(hash-touched nil)
(unbuf-stdin (open-fileno (fileno *stdin*) "u"))
(poll-list (vec (cons unbuf-stdin poll-in))))
(while t
(if (poll poll-list 1000)
(let ((line (get-line unbuf-stdin)))
(when-match `State @s: @status` line
(set [states s] status
hash-touched t))))
(let ((now (time)))
(when (and hash-touched (>= (- now last-time) 1))
(dohash (s status states)
(put-line `State @s: @status`))
(put-string `\e[@(len states)A`)
(flush-stream *stdout*)
(set hash-touched nil
last-time now)))))
プログラムが吹き出ていても、1秒間隔でアップデートになります。このプログラムを使用してテスト入力を生成しています。 20の状態のいずれかをランダムに増やし、ランダムな一時停止で更新を印刷します。
(let* ((nstates 20)
(states (vector nstates 0)))
(while t
(let ((choice (rand nstates)))
(inc [states choice])
(put-line `State @choice: @[states choice]`)
(flush-stream *stdout*)
(if (zerop (rand 4) )
(usleep (rand 500000))))))