Bash 正则表达式匹配

ShellShellBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

本教程将向你介绍 Bash 中的正则表达式(regex)。正则表达式是用于在文本中查找模式的强大工具。通过学习正则表达式,你将大大提高你的 shell 脚本编写技能,从而能够更有效地处理文本、提取数据和自动化任务。本教程专为初学者设计,因此无需具备正则表达式的先验经验。我们将从基础开始,逐步积累你的知识。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL shell(("Shell")) -.-> shell/AdvancedScriptingConceptsGroup(["Advanced Scripting Concepts"]) shell(("Shell")) -.-> shell/SystemInteractionandConfigurationGroup(["System Interaction and Configuration"]) shell(("Shell")) -.-> shell/VariableHandlingGroup(["Variable Handling"]) shell(("Shell")) -.-> shell/ControlFlowGroup(["Control Flow"]) shell/VariableHandlingGroup -.-> shell/variables_decl("Variable Declaration") shell/VariableHandlingGroup -.-> shell/variables_usage("Variable Usage") shell/VariableHandlingGroup -.-> shell/str_manipulation("String Manipulation") shell/ControlFlowGroup -.-> shell/if_else("If-Else Statements") shell/ControlFlowGroup -.-> shell/cond_expr("Conditional Expressions") shell/AdvancedScriptingConceptsGroup -.-> shell/cmd_substitution("Command Substitution") shell/SystemInteractionandConfigurationGroup -.-> shell/globbing_expansion("Globbing and Pathname Expansion") subgraph Lab Skills shell/variables_decl -.-> lab-391551{{"Bash 正则表达式匹配"}} shell/variables_usage -.-> lab-391551{{"Bash 正则表达式匹配"}} shell/str_manipulation -.-> lab-391551{{"Bash 正则表达式匹配"}} shell/if_else -.-> lab-391551{{"Bash 正则表达式匹配"}} shell/cond_expr -.-> lab-391551{{"Bash 正则表达式匹配"}} shell/cmd_substitution -.-> lab-391551{{"Bash 正则表达式匹配"}} shell/globbing_expansion -.-> lab-391551{{"Bash 正则表达式匹配"}} end

理解基本正则表达式和匹配

让我们从正则表达式的基本概念开始。正则表达式是定义一个 搜索模式 的字符序列。你可以把它看作是一种非常强大的文本搜索方式。

以下是基本的构建块:

  • 字面字符: 大多数字符只匹配它们本身。例如,正则表达式 abc 将精确匹配字符串 "abc"。
  • 元字符: 这些是在正则表达式中有特定含义的特殊字符。让我们来看看几个关键的元字符:
    • .(点):匹配 任意单个字符(换行符除外)。因此,a.c 可以匹配 "abc"、"axc"、"a1c" 等等。
    • *(星号):匹配 前一个字符零次或多次ab*c 可以匹配 "ac"、"abc"、"abbc"、"abbbc" 等。
    • ^(脱字符):匹配 行的开头^hello 将匹配以 "hello" 开头的行。
    • $(美元符号):匹配 行的结尾world$ 将匹配以 "world" 结尾的行。
    • [](方括号):定义一个 字符类。它匹配方括号内的 任意一个 字符。[abc] 可以匹配 "a"、"b" 或 "c"。[0-9] 匹配任意单个数字。

现在,让我们创建一个 Bash 脚本来测试我们的理解。使用 touch 命令创建一个名为 regex_test.sh 的文件:

cd ~/project
touch regex_test.sh

接下来,使用文本编辑器(如 nanovim)打开 regex_test.sh 并添加以下代码:

#!/bin/bash

string="Hello World"
if [[ "$string" =~ ^Hello ]]; then
  echo "The string starts with Hello"
else
  echo "The string does not start with Hello"
fi

保存文件并使其可执行:

chmod +x regex_test.sh

最后,运行脚本:

./regex_test.sh
Regex and Matching

输出应该表明该字符串以 "Hello" 开头。

在脚本中使用字符集

使用方括号 [] 定义的字符集允许你从特定组中匹配一个字符。这对于创建更灵活的模式非常有用。

  • 字符范围:[] 内,你可以使用连字符 (-) 来指定一个范围。[a-z] 匹配任何小写字母,[A-Z] 匹配任何大写字母,[0-9] 匹配任何数字。你可以将它们组合起来:[a-zA-Z0-9] 匹配任何字母数字字符。
  • 取反: 如果你将 ^ 作为 [] 内的 第一个 字符,它会对该字符类进行 取反[^0-9] 匹配任何 数字字符。

让我们修改我们的 regex_test.sh 脚本以使用字符集。使用文本编辑器打开 regex_test.sh 并将其内容替换为以下内容:

#!/bin/bash

string="cat"
if [[ "$string" =~ c[a-z]t ]]; then
  echo "Match found!"
else
  echo "No match."
fi

保存文件并运行它:

./regex_test.sh

输出应该显示 "Match found!"。这是因为 c[a-z]t 匹配任何以 'c' 开头、以 't' 结尾的三个字母的字符串,其中中间字符是小写字母。

在脚本中使用量词重复模式

量词用于控制一个字符或字符组应该重复的次数。这极大地增强了你的正则表达式模式的功能。

  • +(加号):匹配前一个字符 一次或多次ab+c 可以匹配 "abc"、"abbc"、"abbbc" 等,但 匹配 "ac"。
  • ?(问号):匹配前一个字符 零次或一次(即让前一个字符可选)。ab?c 可以匹配 "ac" 和 "abc",但不匹配 "abbc"。
  • *(星号):匹配前一个字符 零次或多次。我们之前已经见过这个。
  • {n}:精确匹配前一个字符 n 次a{3} 匹配 "aaa"。
  • {n,}:匹配前一个字符 n 次或更多次a{2,} 匹配 "aa"、"aaa"、"aaaa" 等。
  • {n,m}:匹配前一个字符 n 到 m 次(包含 n 和 m)。a{1,3} 匹配 "a"、"aa" 或 "aaa"。

让我们修改 regex_test.sh 脚本以使用量词。用文本编辑器打开 regex_test.sh 并将其内容替换为以下代码:

#!/bin/bash

string="abbbc"
if [[ "$string" =~ ab+c ]]; then
  echo "Match found!"
else
  echo "No match."
fi

保存文件并运行它:

./regex_test.sh

输出应该显示 "Match found!"。这是因为 ab+c 匹配以 'a' 开头,后面跟着一个或多个 'b',并以 'c' 结尾的字符串。

在脚本中使用捕获组提取数据

括号 () 用于对正则表达式的部分进行 分组。这对于将量词应用于多个字符以及 捕获 匹配的文本非常有用。

当你使用括号时,Bash 会将正则表达式中该部分匹配的文本存储在一个名为 BASH_REMATCH 的特殊数组中。BASH_REMATCH[0] 包含整个匹配的字符串,BASH_REMATCH[1] 包含第一个捕获组匹配的文本,BASH_REMATCH[2] 包含第二个捕获组匹配的文本,依此类推。

让我们修改 regex_test.sh 脚本,使用捕获组来提取数据。用文本编辑器打开 regex_test.sh,并将其内容替换为以下代码:

#!/bin/bash

string="apple123"
if [[ "$string" =~ ^([a-z]+)([0-9]+)$ ]]; then
  fruit="${BASH_REMATCH[1]}"
  number="${BASH_REMATCH[2]}"
  echo "Fruit: $fruit"
else
  echo "No match."
fi

保存文件并运行它:

./regex_test.sh

输出应该包含 "Fruit: apple"。此脚本使用捕获组从字符串中提取水果名称。

在脚本中使用 sed 替换文本

让我们创建一个名为 sed_test.sh 的新脚本,来练习使用 sed

cd ~/project
touch sed_test.sh
chmod +x sed_test.sh

用文本编辑器打开 sed_test.sh 并添加以下内容:

#!/bin/bash

string="apple123"
echo "$string" | sed 's/[0-9]/X/g'

保存文件并运行它:

./sed_test.sh

输出应该是:appleXXX。此脚本使用 sed 将字符串中的所有数字替换为字母 "X"。

总结

本教程向你介绍了 Bash 中的正则表达式(regex)。你学习了基本的正则表达式概念、字符类、量词、分组、捕获,以及如何将正则表达式与 sed 结合使用。通过编写和执行 Bash 脚本,你已经获得了使用这些强大工具的实践经验。请记住通过练习和尝试不同的正则表达式模式来巩固你的理解。