Contents

常见的Linux文本搜索

1. 概述

搜索文本是 Linux 中非常常见的操作。例如,我们想要查找包含特定文本的文件,或者我们想要查找包含特定文本的文件中的行。

在本教程中,我们将一起浏览一些示例,并学习如何使用grep 命令行实用程序在 Linux 中执行一些常见的文本搜索。

2. grep命令

grep命令在一个或多个输入文件中搜索包含与指定模式匹配的行。

它的名字来自ed命令g/re/p(全局搜索正则表达式并打印)。

默认情况下, grep输出匹配的行。grep命令有不同的变体,默认情况下几乎可以在类 Unix 系统的每个发行版上使用。在本教程中,我们将重点关注使用最广泛的GNU grep

3. grep的常用用法

现在让我们看看grep如何帮助我们进行文本搜索的一些实际示例。在本节中,所有示例均使用GNU grep 3.3 版完成。

让我们创建一个名为input.txt的文本文件来帮助我们探索grep命令的结果:

Linux is a great system.
Learning linux is very interesting.
This Linux system has 17 users.
The uptime of this linux system: 77 hours.
File report
There are 100 directories under */*.
There are 250 files under */opt*. 
There are 300 files under */home/root*.
There are 20 mountpoints.

3.1.基本字符串搜索

要了解使用grep执行基本文本搜索是多么简单,让我们在文件中搜索包含字符串“ linux ”的行:

$ grep 'linux' input.txt
Learning linux is very interesting.
The uptime of this linux system: 77 hours.

引用搜索字符串是一种很好的做法。使用单引号还是双引号取决于我们是否希望 shell 在执行grep进程之前扩展表达式。

3.2. 不区分大小写的搜索

使用grep的基本字符串搜索非常简单。如果我们想搜索包含*“linux”“Linux”的行怎么办——也就是说,*进行不区分大小写的搜索?grep-i选项可以帮助我们:**

$ grep -i 'linux' input.txt
Linux is a great system.
Learning linux is very interesting.
This Linux system has 17 users.
The uptime of this linux system: 77 hours.

我们可以看到列出了所有包含linuxLinux的行

3.3. 全词搜索

我们可以使用**-w选项告诉grep将模式视为一个完整的单词**。 例如,让我们在输入文件中查找包含*“is”*作为整个单词的行:

$ grep -w 'is' input.txt 
Linux is a great system.
Learning linux is very interesting.

请注意,包含单词*“this* ”但不包含单词*“is”*的行不包含在结果中。

4. 高级grep用法

4.1. 常用表达

如果我们理解了grep名字的含义,不难想象正则表达式(regex)和grep是好朋友。GNU grep理解三种不同版本的正则表达式语法:

  • BRE(基本正则表达式)
  • ERE(扩展正则表达式)
  • PCRE(Perl 兼容的正则表达式)

**在 GNU grep中,基本语法和扩展语法在功能上没有区别。**但是,PCRE 提供了额外的功能,并且比 BRE 和 ERE 更强大。

默认情况下,grep 将使用 BRE。在 BRE 中,元字符*?* , + , { , | , ( , 和*)失去了它们的特殊含义。我们可以使用反斜杠转义的版本?* , + , { , | , ( , and *)*使它们具有特殊含义。

使用*-E选项,grep*将使用 ERE 语法。在 ERE 中,我们上面提到的元字符具有特殊的含义。如果我们对它们进行反斜杠转义,它们就会失去其特殊含义。

最后,-P选项将告诉 g rep使用 PCRE 语法进行模式匹配。

4.2. 固定字符串搜索

我们了解到grep默认会进行 BRE 搜索。所以我们在前面的例子中给出的模式“ linux ”或“ *is ”也是正则表达式。*它们没有任何具有特殊含义的字符。因此,它们匹配文字文本“ linux ”和“ is ”。

如果我们要搜索的文本包含任何在正则表达式中具有特殊含义的字符(例如,“ . ”或“ * ”),我们必须对这些字符进行转义或使用*-F选项,以告诉grep*执行固定-字符串搜索。

例如,我们可能想要搜索包含“ */opt* ”的行:

$ grep -F '*/opt*' input.txt 
There are 250 files under */opt*.

让我们在不使用*-F*选项的情况下做同样的事情:

$ grep '\*/opt\*' input.txt
There are 250 files under */opt*.

4.3. 反转搜索

我们可以使用grep来搜索不包含特定模式的行。让我们看一个查找所有不包含数字的行的示例:

$ grep -v '[0-9]' input.txt 
Linux is a great system.
Learning linux is very interesting.
File report

上例中的*[0-9]*是匹配单个数字的正则表达式。

如果我们使用*-P选项切换到 PCRE,我们可以使用\d*匹配一个数字并得到相同的结果:

$ grep -vP '\d' input.txt
Linux is a great system.
Learning linux is very interesting.
File report

在上述两个命令的输出中,我们看到空行也被匹配,因为空行也没有数字。

4.4. 仅打印匹配的零件

正如我们所看到的,grep打印与模式匹配的每一行。然而,有时只有匹配的部分对我们来说是有趣的。我们可以使用*-o选项告诉grep*只打印匹配行的匹配部分。

例如,我们可能想要查找所有看起来像目录的字符串:

$ grep -o '/[^/*]*' input.txt
/
/opt
/home
/root

5. 其他grep技巧

5.1. 在匹配之前或之后打印附加上下文行

有时我们希望在结果中看到匹配行之前或之后的行。grep有三个选项来处理额外的上下文行:-B(匹配前)、-A(匹配后)和*-C*(匹配前和匹配后)。

现在,让我们搜索文本*“report”*并打印匹配行之后的三行:

$ grep -A3 'report' input.txt 
File report
There are 100 directories under */*.
There are 250 files under */opt*. 
There are 300 files under */home/root*.

当我们想要检查多条连续线但只知道其中一条与某种模式匹配时,上下文线控制选项会很方便。

例如,YAML 广泛用于配置文件的应用程序中。我们可能只需要查看其中的一部分,而不是查看整个配置文件。例如,要查看 YAML 文件中的数据源配置,我们可以使用grep的*-A*选项:

$ grep -A5 'datasource' src/main/resources/application.yml
datasource:
  driverClassName: ${DATABASE_DRIVER}
  url: ${DATABASE_URL}
  username: ${DATABASE_USERNAME}
  password: ${DATABASE_PASSWORD}

5.2. 计算匹配线

grep中的*-c选项允许我们抑制标准输出,而只打印匹配行的计数。例如,我们想知道有多少行包含“*”*:

$ grep -Fc '*' input.txt
3

grep是一个基于行的搜索实用程序。** -c 选项将输出匹配行的计数而不是模式出现的计数**。这就是为什么上面的命令输出三个而不是六个。

5.3. 递归搜索目录

除了文件,grep也接受一个目录作为输入。一个常见的问题是递归地在目录中搜索并找到包含某种模式的所有文件。

让我们递归搜索*/var/log目录,找到所有包含“boot”的文件。在这里,我们将使用-l选项跳过匹配信息,让grep*仅打印匹配文件的文件名:

$ grep -Rl 'boot' /var/log
/var/log/lxdm.log
/var/log/pacman.log
/var/log/Xorg.0.log
/var/log/nginx/access.log
/var/log/nginx/error.log