Contents

在连续数据流上使用grep

1. 简介

Linux 中有多个实用程序,它们可以作用于文件和标准输入。此外,有些甚至可以对定向到他们的连续数据流采取行动。

在本教程中,我们处理grep (全局正则表达式打印)命令以及我们如何:

  • 将连续的数据流传递给grep
  • 过滤并输出该数据

特别是,我们定义了流并讨论了流操作。之后,我们简要讨论grep如何处理流和文件。接下来,我们看到由特定工具产生的连续流。最后,grep与连续流一起使用,我们还演示了缓冲控制

我们使用 GNU Bash 5.1.4 在 Debian 11 (Bullseye) 上测试了本教程中的代码。它是 POSIX 兼容的,应该可以在任何这样的环境中工作。

2. streams

在最基本的层面上,streams 只是数据的管道。注意“for”这个词的选择,而不是“with”。这是因为它考虑到流的存在不需要数据这一事实。

考虑一个键盘。该输入设备有一个流,但这并不意味着我们不断地敲击键来为其提供数据。在实践中,感兴趣的进程可以订阅流,就好像它们是广播电台一样

他们以多种方式做到这一点:

我们可以在进程之间发送信号以通知它们发生事件,但它们通常不会将实际数据与元数据一起保存。另一方面,套接字主要用于网络。实际上,我们可以将套接字大致等同于网络管道。

这导致我们在一般情况下操纵流——我们的主要兴趣。

3. 流操作

无论是通过流重定向 还是直接管道 ,我们都可以修改和转移流。

3.1. 重定向

一般来说,我们有很多重定向的方法:

$ echo 'Data.' >> file.ext
$ cat file.ext
Data.
$ echo 'Data.' | cat
Data.

在上述两种情况下,我们都在处理重定向操作符。首先,我们使用*»将一些数据echo 到文件中。接下来,我们通过cat (Concatenate)将其输出回来。之后,我们使用 | 管道传输相同的信息直接给cat*。

重要的是,管道几乎总是有缓冲区

3.2. 缓冲

缓冲区的使用通常意味着信息无法通过,除非已经加载了给定的数量以进行传输或一端终止。特别是,可以通过特殊字符终止进程或流。简而言之,我们可以将缓冲区定义为数据临时积累的地方。

一些命令也直接使用缓冲区。

4. grep

grep工具具有内部缓冲功能。它通常在文件操作期间单独运行。另一方面,grep也可以处理流,流本身提供了第二个缓冲层。

4.1. 流

事实上,我们可以通过流重定向将数据传递给grep

$ echo 'Content.' | grep 'Con'
Content.

在这种情况下,我们直接通过管道处理一个字符串。特别是,我们通过管道重定向stdout一旦grep处理完字符串,所有进程都会随着 pipe 终止

但是,还有另一种方法。

4.2. 文件

当然,grep可以直接使用文件名直接作用于文件:

$ echo 'Content.' > file.ext
$ grep 'Con' file.ext
Content.

但是如果我们想监控文件的变化呢?通过与另一个工具相结合,我们可以做到这一点。

*5. tail 的连续流

tail命令有*-f*(跟随)标志,它等待文件更新并将它们添加到输出中,而不是在执行后直接终止。

例如,如果我们在一个终端中开始一个文件的尾随tail并在另一个终端中向该文件发送数据,我们希望在第一个终端中看到相同的数据。让我们看看这个在行动。

首先,我们运行tail

$ tail -f /file.ext

之后,在另一个终端中,我们将数据发送到file.ext

$ echo 'Line.' >> /file.ext

事实上,我们在另一端看到了相同的信息。现在让我们将过滤器添加到等式中。

6. 使用greptail进行连续流处理

这一次,我们将一个连续的流从tail传递到grep

$ tail -f /file.ext | grep 'Line'

接下来,我们在另一个终端中将数据添加到文件中:

$ echo 'Line.' >> /file.ext

现在,根据确切的设置,我们可能看不到输出。为什么?因为缓冲。管道和grep缓冲区都可能延迟输出,直到换行或一定数量的字节

但是,我们可以控制和防止这种情况。

7. 缓冲控制

我们可以使用grep的*–line-buffered*标志来强制在每行终止时刷新其缓冲区,而不是等待具体的字节数:

$ tail -f /file.ext | grep --line-buffered 'Line'

在上述之后,附加到file.ext的每一行都应该产生 output。如果我们不输出换行符,则不会输出:

$ echo -n 'Line.' >> /file.ext

尽管进行了修改,我们仍然可能会遇到管道本身缓冲数据的情况。在这些情况下,我们可以使用一个工具:stdbuf

事实上,我们可以在管道上强制执行相同的行缓冲:

$ stdbuf --output=L tail -f /file.ext | grep --line-buffered 'Line'

使用等于L (行)的*–output*选项,我们在管道的两侧都有行缓冲。

实际上,我们可以使用stdbuf来完全去除缓冲。为此,我们将L替换为0(无缓冲):

$ stdbuf --output=0 tail -f /file.ext | grep 'Line'

根据设置,此行应在对file.ext进行任何修改时立即生成输出。