在Linux find命令中正则表达式的各种用法

在本教程中,我们将讨论将命令 find 与正则表达式(regex)一起使用。我们将了解如何指定正则表达式以进一步优化搜索结果。

正则表达式

在介绍如何在 find 中使用正则表达式之前,我们先来了解一下什么是正则表达式以及正则表达式的构造。

正则表达式(简称 regex)是一种功能强大的工具,由指定搜索模式的字符序列描述。正因为如此,将正则表达式与 find 结合使用,就能以更精简的命令实现更精细的搜索。

正则表达式有不同的类型和格式。下面解释的概念在它们之间是一致的。不过,更高级的功能需要知道使用的是哪种类型的正则表达式,因为它们之间存在差异。下文将详细介绍 find 命令所接受的 regex 类型。

主要正则表达式语法和示例

虽然 regex 有时会让人望而生畏,但它能改进搜索并增强与命令行的交互。只需掌握基本知识,我们就能从中获益。
简单介绍一下,regex 标记可以匹配多个字符:

  • 句号(.):匹配任何字符一次(换行符除外):q.e 将匹配字符串 qwe、qre 和 qee,但不匹配字符串 qe 或 qwwe。
  • 星号(* ):匹配前一个字符/正则表达式的零次或多次出现:qw*e 将匹配字符串 qe、qwe 和 qwwe,但不匹配字符串 qre。
  • 反斜线 (\):用于转义特殊字符,例如,用于搜索句号:q\.e 将匹配字符串 q.e,但不匹配字符串 qre、qee、qe 或 qwwe。
  • 方括号([字符串]):限定只能匹配方括号内字符,任何一个字符可以:q[we]r 将匹配字符串 qwr 和 qer,但不匹配字符串 qr、qwer 或 qwewer。
  • 尖括号 (^):它排除方括号内的内容(尽管在文件中搜索时它也指定行的开头):q[^we]r 将匹配字符串 qar 和 qsr,但不匹配字符串 qwr 或 qer。

根据前面的讨论,.* 将匹配除换行符之外的任何字符的零次或多次出现,这意味着它将匹配任何字符串!

命令描述

find命令的使用可分为两个部分:path和expression:

find [path] [expression]

path是搜索的目录。expression部分还包括在符合搜索条件的文件中可能采取的操作。在这里,find命令有三个与正则表达式相关的选项。我们现在通过一些用例示例来展示它们。以下模型目录将用于示例:

$ tree ./
./
├── a0
├── a0.sh
├── A0.sh
├── a1
├── a1.sh
├── A1.sh
├── a2
├── ca
├── cb
├── cc
└── folder
    ├── a0
    ├── a1
    └── a0folder
        ├── a0
        └── a1

 

使用 -regex

 

第一推荐是使用-regex参数指定正则表达式:

find [path] -regex [regular_expression]

 

使用该命令将搜索目录文件,并返回符合 regular_expression 的文件。regular_expression 搜索目标涵盖了完整的文件名,包括根目录。这意味着,如果在当前目录下查找,正则表达式应以 \.\/ 开头(使用反斜杠转义特殊字符)。

下面的命令查找当前目录(\.\/)中以字母 a 开头、后跟 0 或 1 的文件(使用 -type f 标志):

find ./ -type f -regex '\.\/a[01].*'
./a1
./a0
./a1.sh
./a0.sh

 

文件 a2 没有返回,因为字母 a 后面没有 0 或 1。 我们还可以使用命令在一级目录中搜索,而不是在当前目录中搜索:

find ./ -type f -regex '\.\/[^/]*\/a[01][^/]*'
./folder/a1
./folder/a0

 

最后两个 regexes 有两个不同之处。首先,标记[^/]*\/指的是任何不包含任何斜线([^/]*)的字符串,后面紧接着以字母 a 开头的文件名前的一个斜线(\/)。其次,我们用 [^/]替换了句号,表示字母 a 后面不能再出现斜线。

子目录中的文件不符合 regex:在第一个斜线(当前目录)和紧跟字母 a 的斜线之间有额外的斜线表示子目录(例如 ./folder/a0folder/a0)。

最后,要包含所有子目录中的所有文件,我们可以使用

find ./ -type f -regex '.*a[01].*'
./folder/a0folder
./folder/a0folder/a0
./folder/a0folder/a1
./folder/a0
./folder/a1
./a0
./a1
./a0.sh
./a1.sh

 

使用 -iregex

第二种是-iregex:

find [path] -iregex [regular_expression]

 

该命令执行与 -regex 选项相同的搜索,但忽略搜索模式的字母大小写。为了便于记忆,命令 -iregex 代表不区分大小写的 regex。

如果我们修改之前的一条命令,只查找带点的文件(包括[.]),输出结果如下:

find ./ -type f -regex '\.\/a[01][.].*'
./a0.sh
./a1.sh

使用 -iregex 标志而不是 -regex 标志得到的结果也包括大写字母 A 的文件:

find ./ -type f -iregex '\.\/a[01][.].*'
./a0.sh
./A1.sh
./A0.sh
./a1.sh

使用 -regextype

 

最后,选项 -regextype 用来选择正则表达式的类别:

 

find [path] -regex [regular_expression] -regextype [regex_type]

 

find命令有不同的 regex 类型:

  • findutils
  • emacs (是默认选项,除非另有说明)
  • gnu-awk
  • grep
  • egrep
  • posix-awk
  • posix-basic
  • posix-egrep
  • posix-extended

前面定义的表达式与所有这些类型的 regex 都兼容。不过,在不同的 regex 类型下,更高级的搜索查询可能会产生不同的结果。有一个全面的 GNU 网页专门详细介绍了不同的语法。

 

与 Bash Globbing 的对比

在使用 Linux 一段时间后,bash 的 globbing 功能肯定会出现在 ls 等命令中。让我们看看下面这条命令:

ls *.png

 

它会列出扩展名为 .png 的所有文件。同时,命令:

ls M*.png

 

列出了扩展名为 .png 并以字母 M 开头的所有文件。这就是 Bash globbing 的作用:文件名补全。使用 find 命令搜索文件名时,会用到 Bash globbing 。

尽管它们看起来很相似,但 bash globbing 和正则表达式的语法却不尽相同,这使得问题变得更加复杂。我们将讨论其中两个最相关的差异。在 bash 中,句点(.)代表一个字面意义上的句点,而在 regex 中,句点代表任何一个字符。第一条命令展示了 bash globbing :

find ./ -type f -name 'a*.sh'
./a0.sh
./a1.sh

 

要获得相同的结果,我们可以使用下面的 regex 查找命令:

 

find ./ -type f -regex '\.\/a.*\.sh'
./a0.sh
./a1.sh

 

bash globbing 与正则表达式的另一个区别是星号 (*):在 bash globbing 中,星号代表零个或多个任意字符,但在 regex 中,星号代表零个或多个前一个字符。因此,无论是 bash globbing 还是 regex,类似命令的行为都是不同的。当我们使用 bash globbing 时,下面的命令会返回所有以 c 开头的文件:

find ./ -type f -name 'c*'
./cb
./cc
./ca

 

但是,如果使用 regex 类似的搜索模式,则会返回名称中只包含 c 的所有文件:

find ./ -type f -regex '\.\/c*'
./cc

 

在目录中搜索时,我们应该牢记这些差异,以便更好地使用 bash 语法或正则表达式。

 

 

 

 

 

 

 

 

阅读余下内容
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号