uniq を使用したパイプラインでの隣接行のフィルタリング

uniq を使用したパイプラインでの隣接行のフィルタリング

次のコマンドを使用してテーマの変更を監視しようとしています。

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" | grep -o "uint32 ."

これで出力は次のようになります。

uint32 0
uint32 0
uint32 1
uint32 1
uint32 0
uint32 0
uint32 1
uint32 1

この出力はテーマ遷移に由来します。何らかの理由でトピック通知が2回表示されます。それでは、uniq次のように1つの項目だけを残すようにパイプしたいと思います。

uint32 0
uint32 1
uint32 0
uint32 1

ただし、最後に追加すると、uniq出力は生成されなくなります。

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" | grep -o "uint32 ." | uniq

からman uniq

INPUT(または標準入力)から隣接する一致ラインをフィルタリングし、OUTPUT(または標準出力)に書き込みます。

uniq少なくとも最後の出力ラインは、隣接するラインを検出するためにバッファリングする必要があります。バッファリングしてパイプに沿って渡すことができない理由はありません。提案されているように行バッファリングを調整してみました。ここしかし、結果はまだ私と同じです。

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" | grep -o "uint32 ." | stdbuf -oL -i0 uniq

答え1

これは多くのツールの一般的な動作であり、関数操作を介して基本的な標準Cライブラリの動作から継承されます。入力/出力ストリーム( fopen(3), fwrite(3)...).これは文書化されていますsetvbuf(3)(または使用されなくなったバリエーション)。いくつかの* nixがすべて同じことを言いました。第二SDソラリスGNU/Linux...、しかしPOSIX具体的な内容がなければ、ISO / IEC 9899は難しすぎます。GNUは言う:

新しく開かれたストリームは通常完全にバッファリングされますが、1つの例外は、対話型デバイス(端末など)に接続されたストリームが最初にラインバッファリングされることです。

(返品、標準エラー通常、すべての実装でバッファリングされません。このQ&Aでは重要ではありません。 )

したがって、ほとんどのテキストフィルタリングコマンド(すべてではなく、たとえばcatこの動作はありません)の場合、パイプラインの最後のコマンドでない限り、その出力はラインバッファリングされなくなり、改行は即座に転送をトリガしません。次の注文で処理するデータ。


ここ関連コマンドではuniqありませんが、grep出力が端末からビターミナルに切り替わるからです。 GNUにはgrepこの動作を変更するオプションがあります。--line-buffered:

--line-buffered

出力時にラインバッファリングを使用します。これによりパフォーマンスが低下する可能性があります。

コマンドにアクションを選択する特定のオプションがない場合でも、コマンドを使用できます。stdbufsetvbuf(3)以下を使用して動作を変更します。LD_PRELOAD器具。パイプの終わりにないコマンドのラインバッファリング動作を復元するには、コマンドの前にstdbuf -oL

OPの状況:

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" |
    grep --line-buffered -o "uint32 ." | uniq

または、このgrepコマンドに特定のオプションがない場合:

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" |
    stdbuf -oL grep -o "uint32 ." | uniq

どちらの場合も、uniqパイプラインの最後にある場合はデフォルトの動作を調整する必要はありません。

後でパイプが拡張され、もはやuniqエンドになっていないため、ターミナルに出力されなくなった場合でも動作が変わり、同じ処理が必要です。たとえば、uniq端末でのコマンドの個別のラインバッファリング動作は次のとおりです。

uniq

フルバッファリングに変更:

uniq | cat

ただし、次のように行バッファリングに戻すことができます。

stdbuf -oL uniq | cat

関連情報