Section 34.1: 从与字符串匹配的 regex 中获取捕获的组

a='I am a simple string with digits 1234'
pat='(.*) ([0-9]+)'
[[ "$a" =~ $pat ]]
echo "${BASH_REMATCH[0]}"
echo "${BASH_REMATCH[1]}"
echo "${BASH_REMATCH[2]}"

Output:

I am a simple string with digits 1234
I am a simple string with digits
1234

Section 34.2: 当 glob 不匹配任何内容时的行为

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

如果 glob 没有匹配到任何内容,结果将由 nullglob 和 failglob 选项决定。如果这两个选项都没有设置,那么如果没有匹配到任何内容,Bash 将返回 glob 本身

$ echo no*match
no*match

如果激活了 nullglob,则不会返回任何内容(空):

$ shopt -s nullglob
$ echo no*match

$

如果激活 failglob,则会返回错误信息:

$ shopt -s failglob
$ echo no*match
bash: no match: no*match
$

请注意,failglob 选项优先于 nullglob 选项,也就是说,如果同时设置了 nullglob 和 failglob,那么在不匹配的情况下,将返回错误信息。

Section 34.3: 检查字符串是否与正则表达式匹配

Version ≥ 3.0

Check if a string consists in exactly 8 digits:
$ date=20150624
$ [[ $date =~ ^[0-9]{8}$ ]] && echo "yes" || echo "no"
yes
$ date=hello
$ [[ $date =~ ^[0-9]{8}$ ]] && echo "yes" || echo "no"
no

Section 34.4: regex 匹配

pat='[^0-9]+([0-9]+)'
s='I am a string with some digits 1024'
[[ $s =~ $pat ]] # $pat must be unquoted
echo "${BASH_REMATCH[0]}"
echo "${BASH_REMATCH[1]}"

Output:

I am a string with some digits 1024
1024

我们也可以这样做,而不是将 regex 赋值给变量 ($pat):

[[ $s =~ [^0-9]+([0-9]+) ]]
  • 说明

  • [[$s=~$pat]] 结构执行 regex 匹配

  • 捕获的分组(即匹配结果)在名为 BASH_REMATCH 的数组中可用

  • BASH_REMATCH 数组中的第 0 个索引是总匹配结果

  • BASH_REMATCH 数组中的第 i 个索引是第 i 个捕获组,其中 i = 1、2、3 ...

Section 34.5: The * glob

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

星号 * 可能是最常用的 glob。它可以简单地匹配任何字符串

$ echo *acy
macy stacy tracy

单个 * 不会匹配子文件夹中的文件和文件夹

$ echo *
emptyfolder folder macy stacy tracy
$ echo folder/*
folder/anotherfolder folder/subfolder

Section 34.6: The ** glob

Version ≥ 4.0

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -s globstar

Bash 可以将两个相邻的星号解释为一个 glob。激活 globstar 选项后,可以用来匹配目录结构中更深的文件夹

echo **
emptyfolder folder folder/anotherfolder folder/anotherfolder/content
folder/anotherfolder/content/deepfolder folder/anotherfolder/content/deepfolder/file
folder/subfolder folder/subfolder/content folder/subfolder/content/deepfolder
folder/subfolder/content/deepfolder/file macy stacy tracy

可以把 ** 视为路径扩展,无论路径有多深。本例匹配任何以 deep 开头的文件或文件夹,无论其嵌套多深:

$ echo **/deep*
folder/anotherfolder/content/deepfolder folder/subfolder/content/deepfolder

Section 34.7: The ? glob

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

? 只需匹配一个字符即可

$ echo ?acy
macy
$ echo ??acy
stacy tracy

Section 34.8: The [ ] glob

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

如果需要匹配特定字符,则可以使用[]。[]内的任何字符都将精确匹配一次。

$ echo [m]acy
macy
$ echo [st][tr]acy
stacy tracy

然而,[] glob 的功能远不止于此。它还允许负匹配,甚至匹配字符范围和字符类别。使用 ! 或 ^ 作为 [ 后的第一个字符,就可以实现负匹配。我们可以通过以下方式匹配 stacy

$ echo [!t][^r]acy
stacy

在这里,我们要告诉 bash,只匹配不以 t 开头、第二个字母不是 r 且以 acy 结尾的文件。

用连字符 (-) 分隔一对字符可以匹配范围。介于这两个字符之间的任何字符(包括在内)都将被匹配。例如,[r-t]等同于[rst]。

$ echo [r-t][r-t]acy
stacy tracy

字符类可以用 [:class:] 匹配,例如,为了匹配包含空格的文件

$ echo *[[:blank:]]*
file with space

Section 34.9: 匹配隐藏文件

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

Bash 内置选项 dotglob 允许匹配隐藏的文件和文件夹,即以 .开头的文件和文件夹。

$ shopt -s dotglob
$ echo *
file with space folder .hiddenfile macy stacy tracy

Section 34.10: 不区分大小写匹配

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

设置 nocaseglob 选项将以不区分大小写的方式匹配 glob

$ echo M*
M*
$ shopt -s nocaseglob
$ echo M*
macy

Section 34.11: 扩展 globbing

Version ≥ 2.02

准备工作

$ mkdir globbing
$ cd globbing
$ mkdir -p folder/{sub,another}folder/content/deepfolder/
touch macy stacy tracy "file with space" folder/{sub,another}folder/content/deepfolder/file
.hiddenfile
$ shopt -u nullglob
$ shopt -u failglob
$ shopt -u dotglob
$ shopt -u nocaseglob
$ shopt -u extglob
$ shopt -u globstar

Bash 内置的 extglob 选项可以扩展 glob 的匹配功能

shopt -s extglob

下列子模式包含有效的扩展 globs:

  • ?(pattern-list)– 匹配给定模式的零次或一次出现

  • *(pattern-list) – 匹配给定模式的零次或多次出现

  • +(pattern-list) – 匹配给定模式的一次或多次出现

  • @(pattern-list) – 匹配给定模式之一

  • !(pattern-list) – 除给定模式之一外,匹配其他任何模式

模式列表是一个用 | 分隔的 globs 列表。

$ echo *([r-t])acy
stacy tracy

$ echo *([r-t]|m)acy
macy stacy tracy

$ echo ?([a-z])acy
macy

模式列表本身可以是另一个嵌套的扩展 glob。在上面的例子中,我们看到可以用 *(r-t)来匹配 tracy 和 stacy。这个扩展 glob 本身可以在否定的扩展 glob !(pattern-list) 中使用,以匹配 macy

$ echo !(*([r-t]))acy
macy

只要开头字母 r、s 和 t 的出现次数不为 0 或多于 0 次,就与之匹配,因此只有 macy 可能匹配。