Bash 零基础教程

正则表达式

正则表达式(Regular expressions),通常简称为 “regex” 或 “regexp”,是一种用于在文本中进行模式匹配的强大工具。它们提供了一种简洁且灵活的方式来“查找”(搜索)、“查找并替换”(替换)或“验证”(匹配)符合特定模式的文本字符串。

掌握正则表达式可以解锁高效的文本处理能力,这是处理数据验证、提取、日志分析以及代码重构等任务的关键。虽然它的语法初看起来可能令人心生畏惧,但只要理解了基本概念,你就能在各种应用场景中发挥其巨大威力。本章提供了对正则表达式的全面介绍,为你在后续章节中使用 grepsedawk 等工具打下坚实的基础。

1. 正则表达式基础语法

正则表达式由字面量字符(literal characters)和特殊字符(通常称为元字符,metacharacters)组成。字面量字符匹配它们自身,而元字符具有特殊的含义,可以实现复杂的模式匹配。让我们来探索一些基本的构建模块。

1.1 字面量字符 (Literal Characters)

最简单的正则表达式仅由字面量字符组成。例如,正则表达式 hello 将完全匹配字符串 "hello"。区分大小写非常重要,因此默认情况下 Hello 不会匹配 hello(尽管存在使其不区分大小写匹配的选项,我们将在下一章介绍 grep 时涵盖这些内容)。

示例:
正则表达式 bash 将在以下字符串中匹配 "bash":

  • "I love bash scripting."
  • "The bash shell is powerful."

不会匹配:

  • "BASH scripting is fun." (区分大小写)
  • "I use zsh." (不同的字面量字符)

1.2 元字符 (Metacharacters)

元字符是正则表达式强大功能的绝对核心。以下是一些必学的元字符:

  • . (点号 / Dot): 匹配除换行符以外的任意单个字符

示例: 正则表达式 a.c

    • 匹配: "abc", "a1c", "a c"
    • 不匹配: "ac" (缺少一个字符), "abbc" ("a" 和 "c" 之间有多于一个字符), "a\nc" (换行符)
  • ^(脱字符 / Caret): 匹配一行的开头

示例: 正则表达式 ^hello

    • 匹配: "hello world" (因为 "hello" 在行的开头)
    • 不匹配: "world hello", " hello" (因为前面有空格)
  • $(美元符号 / Dollar): 匹配一行的结尾

示例: 正则表达式 world$

    • 匹配: "hello world" (因为 "world" 在行的结尾)
    • 不匹配: "world hello", "world " (末尾有空格), "world is great"
  • [](字符类 / Character Class): 匹配方括号内的任意单个字符。你也可以指定一个字符范围。

示例:

    • [aeiou] 将匹配任意单个小写元音字母 ("a", "e", "i", "o", "u")。
    • [0-9] 将匹配任意单个数字 ("0", "1", "9")。
    • [a-zA-Z] 将匹配任意单个小写或大写字母 ("a", "Z")。
    • 正则表达式 [abc]
      • 匹配: "a", "b", "c"
      • 不匹配: "d", "ab" (它只匹配单个字符)
  • [^](反向字符类 / Negated Character Class): 匹配在方括号内的任意单个字符。

示例: 正则表达式 [^0-9] 将匹配任意非数字的单个字符。

    • 匹配: "a", " " (空格), "$"
    • 不匹配: "0", "5"
  • \(反斜杠 / Backslash): 转义元字符,使其被视为字面量字符。

示例: 正则表达式 \. 将匹配字面意义上的点号 (.)。如果没有反斜杠,. 将匹配任意字符。

    • 匹配: "file.txt"
    • 不匹配: "fileatxt" (因为 . 在这里被当作字面量的点号,而不是任意字符)

1.3 量词 (Quantifiers)

量词用于指定其前面的元素可以出现的次数。

  • * (星号 / Asterisk): 匹配前面的元素零次或多次

示例: 正则表达式 ab*c

    • 匹配: "ac" (零个 'b'), "abc" (一个 'b'), "abbc" (两个 'b'), "abbbbbbc"
    • 不匹配: "adc" (因为不存在 'b' 且包含了其他字符)
  • + (加号 / Plus): 匹配前面的元素一次或多次

示例: 正则表达式 ab+c

    • 匹配: "abc" (一个 'b'), "abbc" (两个 'b'), "abbbbbbc"
    • 不匹配: "ac" (零个 'b'), "adc"
  • ?(问号 / Question Mark): 匹配前面的元素零次或一次

示例: 正则表达式 ab?c

    • 匹配: "ac" (零个 'b'), "abc" (一个 'b')
    • 不匹配: "abbc" (两个 'b'), "adc"
  • {n}:匹配前面的元素恰好 n 次

示例: 正则表达式 a{3}b

    • 匹配: "aaab"
    • 不匹配: "aab", "aaaab"
  • {n,}:匹配前面的元素至少 n 次(n 次或更多次)。

示例: 正则表达式 a{2,}b

    • 匹配: "aab", "aaab", "aaaaaaaab"
    • 不匹配: "ab"
  • {n,m}:匹配前面的元素在 n 到 m 次之间(包含 n 和 m)。

示例: 正则表达式 a{2,4}b

    • 匹配: "aab", "aaab", "aaaab"
    • 不匹配: "ab", "aaaaab"

1.4 锚点 (Anchors)

锚点(如 ^$)本身不匹配任何字符,而是匹配字符串中的位置

  • \b:匹配一个单词边界(即单词字符和非单词字符之间的位置)。单词字符通常是字母、数字和下划线。

示例: 正则表达式 \bcat\b

    • 匹配: "cat" (作为一个完整的单词), " cat ", "cat."
    • 不匹配: "category", "tomcat"
    • 解释\b 确保你匹配的是完整的单词 "cat",而不是其他单词的一部分。

1.5 分组与分支 (Grouping and Alternation)

  • () (圆括号 / Parentheses): 将正则表达式的多个部分分组在一起。这允许你将量词或其他操作应用于整个组。同时它也会创建捕获组,可以在以后被引用(在讨论 sed 时会更详细地介绍)。

示例: 正则表达式 (ab)+

    • 匹配: "ab", "abab", "ababab"
    • 不匹配: "a", "b", "ac"

|(管道符 / Pipe): 表示分支(OR / 或)。匹配管道符前面或后面的表达式。

示例: 正则表达式 cat|dog

    • 匹配: "cat", "dog"
    • 不匹配: "bird", "catdog" (它匹配 "cat" 或 "dog",而不是两者连续出现)

1.6 字符类简写 (Character Classes Shorthands)

有几种常用的速记字符类:

  • \d:匹配任意数字(等同于 [0-9])。
  • \D:匹配任意非数字(等同于 [^0-9])。
  • \w:匹配任意单词字符(字母数字和下划线;等同于 [a-zA-Z0-9_])。
  • \W:匹配任意非单词字符(等同于 [^a-zA-Z0-9_])。
  • \s:匹配任意空白字符(空格、制表符、换行符等)。
  • \S:匹配任意非空白字符。

示例: 正则表达式 \d+

    • 匹配: "1", "123", "1234567890"
    • 不匹配: "a", "abc"

2. 正则表达式实战示例

让我们结合这些概念,看一些实际的例子:

匹配 YYYY-MM-DD 格式的日期:

\d{4}-\d{2}-\d{2}
  • 解析: 此正则匹配四个数字 (\d{4}),后跟一个连字符,接着是两个数字 (\d{2}),再跟一个连字符,最后是两个数字 (\d{2})。

匹配电子邮件地址(简化版):

\w+@\w+\.\w+
  • 解析: 此正则匹配一个或多个单词字符 (\w+),后跟一个 @ 符号,接着是一个或多个单词字符 (\w+),后跟一个点号 (\.),最后是一个或多个单词字符 (\w+)。
  • 注意:这是一个极其简化的示例,并不能覆盖所有有效的电子邮件地址格式。一个真正健壮的电子邮件验证正则表达式要复杂得多。

匹配以 "Error" 开头的行(不区分大小写):

^Error
  • 解析: 要在 grep 中使其不区分大小写(正如你将在下一章学到的),你需要使用 -i 标志:grep -i "^error"

匹配 (XXX) XXX-XXXX 格式的电话号码:

\(\d{3}\) \d{3}-\d{4}
  • 解析: 此正则匹配一个左括号 \((被转义,因为 ( 是元字符),后跟三个数字 (\d{3}),接着是一个右括号 \)(已转义),后跟一个空格,接着是三个数字 (\d{3}),后跟一个连字符,最后是四个数字 (\d{4})。

3. 实际应用场景

正则表达式在软件开发、系统管理和数据分析中被广泛使用。以下是一些例子:

  • 日志分析: 分析日志文件以寻找特定的错误消息或模式,从而识别系统问题。例如,使用正则表达式从日志文件中提取所有包含 "error" 单词的行。
  • 数据验证: 验证表单中的用户输入,以确保其符合特定格式,例如电子邮件地址、电话号码或日期。
  • 代码重构: 使用正则表达式查找和替换代码模式,例如重命名变量或更新函数调用。
  • 数据提取: 从非结构化文本中提取特定数据,例如从网站上提取产品价格。
  • 安全防御: 入侵检测系统使用正则表达式来识别网络流量中的恶意模式。

对于“自动化系统管理任务”案例研究,正则表达式可应用于验证配置文件。想象一下,需要确保网络配置文件中的所有 IP 地址都是合法的。正则表达式可以快速检查每个 IP 地址是否符合正确的格式(四组介于 0 和 255 之间的数字,由点号分隔)。