6个使用grep递归示例的实际方案

时间:2020-01-09 10:38:47  来源:igfitidea点击:

如何在Linux服务器的所有目录和子目录中使用grep表示模式?
是否可以递归执行grep?
如何以grep的方式在多个目录中递归提供模式或者字符串?

使用grep实用程序,我们有两个参数可以从grep的手册页中递归执行grep。

-r, --recursive
      Read  all files under each directory, recursively, following symbolic links only if they are on the command line.
      Note that if no file operand is given, grep searches the working directory.  This is equivalent to the -d recurse
      option.
-R, --dereference-recursive
      Read all files under each directory, recursively.  Follow all symbolic links, unlike -r.

在本教程中,我将通过示例共享多种方法,以针对不同的场景递归grep,我们可以选择最适合自己需求的方法。

1.在所有子目录内递归地对文件中的字符串进行Grep

我们将介绍的第一种情况是我们必须在所有子目录内的字符串中执行grep。
为此,我们可以直接使用grep -r,而无需任何其他参数。
一般的语法是:

grep [-r|--recursive] [PATH]

示例1:在/tmp/dir中递归搜索字符串" test"

要获取所有在/tmp/dir下包含test字符串的文件,可以使用

# grep -r test /tmp/dir/*

或者

# grep -r test /tmp/dir/

或者在目标路径内导航

# cd /tmp/dir

和grep为字符串

# grep -r test .

所有这些命令将在目录/tmp/dir和此文件夹内的所有子目录中搜索包含单词test或者带有单词test的任何匹配字符串的所有文件。

说明:

该命令将搜索所有包含test的字符串,例如latest,testing等。

2.在所有子目录内递归文件中的Grep精确匹配

在此示例中,我们将使用grep获取确切的模式,而不是包含字符串的所有匹配单词。
因此,假设现在我们只希望grep包含test的文件,但是我们不应该从诸如testing,latest等匹配模式中获取输出。
一般的语法是:

grep [-r|--recursive] [-w|--word-regexp] [PATH]

示例1:递归精确匹配的Grep

要获取所有在/tmp/dir下包含精确模式test字符串的文件,可以使用

# grep -rw test /tmp/dir/*

或者

# grep -rw test /tmp/dir/

或者在目标路径内导航

# cd /tmp/dir

和grep为字符串

# grep -rw test .

3.仅在预定义文件中为字符串提供Grep

我们还可以使用纯文本格式或者regex定义文件名,应对其进行搜索以grep提供的模式。
例如,我希望grep输入test字符串,但仅在文件名中包含lvm或者linux的文件中使用。

在以下示例中,我们将在文件名中包含lvmlinux的文件中搜索测试字符串。
现在我们可以拥有一个文件,例如my-lvm.conf,dummy-lvm.conf和store-linux.config,因此当我们使用lvm和linux作为我们的文件时,所有这些文件都可以用于文件名的正则表达式:

方法1:与exec一起使用find

在这个例子中,我们将使用带有find的exec和find来搜索特定的文件,并使用grep作为字符串。
与单个文件名一起使用的"语法":

find PATH -type f -name <filename> -exec grep [args] [pattern] {} +

与多个文件名一起使用的"语法":

find PATH -type f \( -name <filename-1> -o -name <filename-2> \) -exec grep [args] [pattern] {} +

因此,以下示例将涵盖我们的方案。

# find /tmp/\( -name "*linux*" -o -name "*lvm*" \)  -type f -exec grep -w test {} +

使用exec查找以递归搜索

方法2:与xargs一起使用find

在此示例中,我们将为具有多个文件名的字符串将findxargs组合为grep
与单个文件名一起使用的"语法":

find PATH -type f -name <filename> | xargs grep [args] [pattern]

替代方法:

find PATH -type f -name <filename> -print0 xargs -0 grep [args] [pattern]

与多个文件名一起使用的"语法":

find PATH -type f \( -name <filename-1> -o -name <filename-2> \) | xargs grep [args] [pattern]

因此,下面的示例可用于搜索与lvmlinuxgrep匹配的所有文件名以test的字符串

# find /tmp/\( -name "*linux*" -o -name "*lvm*" \)  -type f | xargs grep -w test

或者

# find /tmp/\( -name "*linux*" -o -name "*lvm*" \)  -type f -print0 | xargs -0 grep -w test

使用xargs查找以递归搜索

说明:

使用find时,我们不需要将-r或者--recursivegrep一起使用,因为默认情况下,find会在所有子目录中搜索

方法3:将grep与--include一起使用

我们不必依赖第三个工具来搜索某些特定文件中的字符串,grep本身可以选择仅搜索提供的文件。

--include=GLOB
        Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).

--include递归使用grep的语法是:

grep -r --include=GLOB PATTERN PATH

我们可以多次使用--include来通过grep指定多个文件名。

# grep --include=*lvm* --include=*linux* -rw test /tmp/dir

用--include递归grep

4.通过排除预定义文件来对字符串进行Grep

现在类似于上一节,我们将使用find和其他工具排除某些预定义的文件名,同时尝试递归grep任何模式或者字符串。
在以下示例中,我们将在所有文件中搜索测试字符串,但文件名中包含lvmlinux的文件除外

方法1:与exec一起使用find(NOT运算符)

在这个例子中,我们将使用find命令排除某些文件,同时通过使用NOT()运算符来查找字符串。
使用此方法的一般syntax为:

find PATH -type f ! -name <filename-1> ! -name <filename-2> -exec grep [args] [pattern] {} +

在此,我们可以提供要排除在搜索范围之外的多个文件。

# find /tmp/ ! -name "*linux*" ! -name "*lvm*" -type f -exec grep -w test {} +

使用NOT运算符查找exec以排除文件

如我们所见,我们在某些正则表达式中使用了NOT(!!)运算符,以排除名称中带有linuxlvm的所有文件名。

方法2:与exec一起使用查找(修剪)

我们也可以在使用prune的exec中使用find和exec来排除某些文件,同时grepping某些模式。
使用该命令的一般语法是:

find PATH \( -name <filename-1> -o -name <filename-2> \) -prune -o -type f -exec grep [args] [pattern] {} +

现在,我们可以在示例中使用"语法"。
这将打印文件名和grepped的" PATTERN"

find /tmp/\( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -exec grep -w test {} +

用prune查找exec以排除文件1

或者,我们也可以使用grep -H参数来显示文件名:

# find /tmp/\( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -exec grep -wH test {} \;

用prune查找exec以排除文件2

如果我们不希望使用文件名,则可以使用:

# find /tmp/\( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -exec grep -w test {} \;

用prune查找exec以排除文件3

方法3:与xargs使用查找(NOT运算符)

现在与使用execfind类似,我们还可以将相同的NOT()运算符与xargs一起使用。
一般的语法是:

find PATH -type f ! -name <filename-1> ! -name <filename-2> | xargs grep [args] [pattern]

替代方法:

find PATH -type f ! -name <filename-1> ! -name <filename-2> -print0 xargs -0 grep [args] [pattern]

现在,我们将使用find命令以递归方式将syntax修改为示例以适应grep`:

# find /tmp/ ! -name "*linux*" ! -name "*lvm*" -type f  -print0 | xargs -0 grep -w test

使用NOT运算符查找xargs以排除文件-1

或者

# find /tmp/ ! -name "*linux*" ! -name "*lvm*" -type f  | xargs  grep -w test

使用NOT运算符查找xargs以排除文件2

方法4:将查找与xargs一起使用(修剪)

再次类似于使用exec查找,我们可以将find与xargsprune`结合使用以排除某些文件。
实现此目的的"语法"为:

find PATH -type f \( -name <filename-1> -o -name <filename-2> \) -prune -o -print0 | xargs -0 grep [args] [pattern]

让我们在示例中使用以下语法:

# find /tmp/\( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -print0 | xargs -0  grep -w test

用prune查找xargs以排除文件

方法5:将grep与--exclude一起使用

现在,上述所有方法对于初学者来说都可能有点复杂,所以不用担心,我们有一个支持grep的参数,即--exclude = GLOB,当grep在目录中搜索模式时,我们可以使用该参数排除某些文件和子目录。
要使用的语法是:

grep -r --exclude=GLOB PATTERN PATH

其中我们可以用正则表达式或者要排除的文件的实际文件名替换GLOB
我们可以多次使用--exclude = GLOB来排除多个文件

提示:

我们也可以在单个命令中将--include--excludegrep结合使用

因此,我们可以使用下面的示例来获得结果,而无需使用find命令:

# grep -r --exclude="*lvm*" --exclude="*linux*" test /tmp/dir/

grep使用--exclude递归

5.使用递归搜索的多种模式的Grep

这里可能有两种可能的情况

  • grep用于所有目录和子目录中的多个字符串

  • grep用于同一文件中的多个字符串

由于本教程更多关于grep递归,因此第一个问题与本教程有关,但我将同时介绍这两个方面。

示例1:Grep目录和子目录中的多种模式

使用grep,我们可以使用-e PATTERN一次定义多个模式。
相同的syntax将是:

grep [args] PATH -e PATTERN-1 -e PATTERN-2 ..

例如,我希望grep在/tmp/dir和子目录下的所有文件内为模式lvmtest

# grep -rw '/tmp/dir/' -e test -e lvm

grep递归多重模式

同样,我们可以为递归grep所需要的许多模式添加-e PATTERN。

示例2:单个文件中多个字符串的Grep

对于同一个文件中的多个字符串,我们可以对-g PATTER-e PATTERN使用相同的语法。
仅提供文件名,而不是提供目录位置:

# grep -e "lvm" -e "test" lvm.conf

或者

# grep "lvm\|test" lvm.conf

要同时打印文件名,请使用-H或者--with-filename和grep,如下所示:

# grep -H "lvm\|test" lvm.conf

6. Grep递归处理具有符号链接的文件

默认情况下,grep忽略查找符号链接文件,仅搜索文本文件格式。
为了克服这个问题,即确保grep在搜索字符串时也可以查看符号链接

-R, --dereference-recursive
      Read all files under each directory, recursively.  Follow all symbolic links, unlike -r.

此示例要使用的"语法":

grep -R PATTERN PATH

示例1:在所有符号链接和/tmp/dir下的文件" test"下的Grep

为此,我们将使用:

# grep -R test /tmp/dir/

文件和符号链接中的grep