使用 awk 格式化 grep 输出。简单案例和背景案例

使用 awk 格式化 grep 输出。简单案例和背景案例

我正在努力解决这个问题。我有这一行:

mplayer *.* 2>/dev/null | grep Playing

它刚刚启动mplayer,并且只有匹配的行打印在屏幕上。每当我更改当前播放的媒体时,这也适用。Playing filename

我想知道是否可以“格式化” grep 的输出。例如,如果输出是:

Playing Pink_Floyd-Wish_You_Were_Here.mp3  # I get this at the beginning
Playing Pearl_Jam-Once.mp3                 # I get this after I change media inside mplayer

那么我会有类似的东西:

Mplayer: Playing Pink_Floyd-Wish_You_Were_Here.mp3
Mplayer: Playing Pearl_Jam-Once.mp3

为此,我决定使用 awk:

mplayer *.* 2>/dev/null | grep Playing | awk '{print "Mplayer: "$1}'

但在这种情况下什么也没有发生;我没有输出!

我的问题不是面向解决mplayer的问题,而是为了对bash中的管道有更深入的了解。

例如,如果我使用以下内容:

echo a_song.mp3 | awk '{print "Mplayer: "$1}'

我得到我想要的

Mplayer: a_song.mp3

为什么第一个命令不起作用?

如果我想在后台运行多个这样的进程,我该怎么办?

答案1

许多grep当标准输出为终端时,实现将使用行缓冲。当标准输出是终端时,它通常是一个交互式会话,您希望尽快获取数据。因此grep,一旦看到换行符,就会将数据写入标准输出。

当标准输出不是终端(通常意味着非交互式会话)时,grep将使用块缓冲区。这意味着grep看到换行符时不会立即写入标准输出。grep在写入标准输出之前收集大量数据(在 Linux 中为 4096 字节)。

某些grep版本,例如GNU grep或者BSD grep--行缓冲选项。grep当看到换行符时,它总是写入标准输出。所以你的例子变成:

mplayer *.* 2>/dev/null | grep --line-buffered Playing | awk '{print "Mplayer: "$1}'

如果您的grep版本没有--line-buffer,您可以使用以下命令完成所有操作awk

mplayer *.* 2>/dev/null | awk '/Playing/{print "Mplayer: "$1}'

GNU coreutils 有一个工具标准缓冲区用于修改命令的缓冲。您始终可以使用以下命令在标准输出中强制行缓冲区:

stdbuf -oL command

还有解缓冲仅禁用输出缓冲的命令。

进一步阅读

相关内容