使用uniq过滤管道中的相邻行

Pav*_*nes 11 grep uniq

我正在尝试使用以下命令监视主题更改:

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" | grep -o "uint32 ."
Run Code Online (Sandbox Code Playgroud)

现在的输出看起来像这样:

uint32 0
uint32 0
uint32 1
uint32 1
uint32 0
uint32 0
uint32 1
uint32 1
Run Code Online (Sandbox Code Playgroud)

此输出来自主题切换。由于某种原因,主题通知显示两次。现在我想将其通过管道传输到uniq,因此我只保留一个条目,如下所示:

uint32 0
uint32 1
uint32 0
uint32 1
Run Code Online (Sandbox Code Playgroud)

然而,uniq在最后追加不会再产生任何输出。

uint32 0
uint32 0
uint32 1
uint32 1
uint32 0
uint32 0
uint32 1
uint32 1
Run Code Online (Sandbox Code Playgroud)

man uniq

从 INPUT(或标准输入)中过滤相邻的匹配行,写入 OUTPUT(或标准输出)。

uniq需要缓冲至少最后一个输出行才能检测相邻行,我看不出有任何原因它不能缓冲它并沿着管道传递它。我已经尝试按照此处的建议调整行缓冲,但结果对我来说仍然相同。

uint32 0
uint32 1
uint32 0
uint32 1
Run Code Online (Sandbox Code Playgroud)

A.B*_*A.B 27

这是许多工具的常见行为,继承自带有操作I/O 流的函数的默认标准 C 库行为(fopen(3), fwrite(3)...)。这已记录在setvbuf(3)(或已弃用的变体)中。几个 *nixes 都说了同样的话: * BSD 、 Solaris GNU / Linux ...,但POSIX没有指定它,并且 ISO/IEC 9899 太难以捉摸GNU 告诉

新打开的流通常是完全缓冲的,但有一个例外:连接到交互式设备(例如终端)的流最初是行缓冲的。

(此外,stderr在所有实现中通常都是无缓冲的。这对于这个 Q/A 来说并不重要。)

因此,对于大多数文本过滤命令(并非全部,例如cat没有此行为),只要它不是管道中的最后一个命令,其输出就不再进行行缓冲,并且换行不会触发立即发送数据下一个要处理的命令。


这里相关命令不是uniqbutgrep,因为它的输出从终端切换到非终端。GNUgrep有一个选项可以改变这种行为--line-buffered::

--line-buffered

在输出上使用行缓冲。这可能会导致性能损失。

如果该命令没有特定的选项来选择行为,人们仍然可以使用通过机制stdbuf来改变行为的命令。要恢复不在管道末尾的命令的行缓冲行为,可以为该命令添加前缀.setvbuf(3)LD_PRELOADstdbuf -oL

对于OP的情况:

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" |
    grep --line-buffered -o "uint32 ." | uniq
Run Code Online (Sandbox Code Playgroud)

或者如果此grep命令也没有特定选项:

dbus-monitor --session "interface='org.freedesktop.portal.Settings', member=SettingChanged" |
    stdbuf -oL grep -o "uint32 ." | uniq
Run Code Online (Sandbox Code Playgroud)

请注意,在这两种情况下,uniq处于管道末端不需要对其默认行为进行任何调整。

如果稍后管道被扩充并且uniq不再位于末端,从而不再输出到终端,它也会改变行为并且需要相同的处理。例如,命令uniq在终端上单独的行缓冲行为:

uniq
Run Code Online (Sandbox Code Playgroud)

更改为全缓冲:

uniq | cat
Run Code Online (Sandbox Code Playgroud)

但可以通过以下方式反转为行缓冲:

stdbuf -oL uniq | cat
Run Code Online (Sandbox Code Playgroud)