常见的Linux文本搜索

评论 0 浏览 0 2019-10-13

1.概述

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

在本教程中,我们将通过一些示例一起学习如何使用 grep command-line 实用程序 在 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.

为了看看使用grep进行基本的文本搜索是多么简单,让我们搜索我们的文件中包含字符串“linux“的行。

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

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

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的行都被列出来。

我们可以使用-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中,元字符?+{|()失去了其特殊含义。我们可以使用反斜线省略的版本\?, \+, \{, \|, \(, 和\) 来使它们具有特殊含义。

有了-E 选项,grep将以ERE语法工作。在ERE中,我们上面提到的元字符有特殊含义。如果我们对它们进行反斜线转码,它们就会失去其特殊含义。

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

我们已经知道grep默认会做BRE搜索。所以我们在前面的例子中给出的模式“linux”或“is”也是regex。它们没有任何具有特殊意义的字符。因此,它们与字面文本“linux”和“is“相符。

如果我们要搜索的文本包含任何在regex中具有特殊意义的字符(例如,“.”或“*“),我们必须转义这些字符或使用-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*.

我们可以使用grep来搜索不包含某种模式的行。让我们看一个例子,找到所有不含数字的行。

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


File report

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

如果我们改用PCRE的-P选项,我们可以用\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文件中的datasource配置,我们可以利用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选项将输出匹配的行数,而不是模式出现的次数。这就是为什么上面的命令输出3个而不是6个。

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

6.结论

在这篇文章中,我们已经学会了如何使用grep命令来做简单的文本搜索,以及如何控制输出。

简单地说,我们已经看到了grep是如何高效、快速地查找文本的,是我们Linux命令库中的一个伟大工具。

最后更新2022-12-02
0 个评论
标签