我正在尝试使用以下命令监视主题更改:
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
此输出来自主题切换。主题通知出于某种原因出现了两次。现在我想将其通过管道传输,uniq
这样我只剩下一个条目,如下所示:
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)
(或已弃用的变体)中。几个 *nixes 都说同样的事情:*乙SD,索拉里斯,GNU/Linux..., 但POSIX没有具体说明,ISO/IEC 9899 太难以捉摸。GNU 告诉:
新打开的流通常是完全缓冲的,但有一个例外:连接到交互式设备(例如终端)的流最初是行缓冲的。
(还,标准错误在所有实现中通常都是无缓冲的。对于这个问答来说并不重要。)
因此,对于大多数文本过滤命令(并非全部,例如cat
没有此行为),只要它不是管道中的最后一个命令,其输出就不再进行行缓冲,并且换行不会触发立即发送数据下一个要处理的命令。
这里相关命令不是uniq
但是grep
因为它的输出从终端切换到非终端。 GNUgrep
有一个选项可以改变这种行为:--line-buffered
:
--line-buffered
在输出上使用行缓冲。这可能会导致性能损失。
如果该命令没有特定的选项来选择行为,人们仍然可以使用该命令stdbuf
setvbuf(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