Sed 正则表达式
Sed - 精通正则表达式
Section titled “Sed - 精通正则表达式”正则表达式(通常缩写为 regex)是 Sed 强大和高效的基石,使它能够执行复杂的文本操作。对于任何命令行用户来说,对正则表达式有扎实的理解是极有价值的。
与许多 GNU/Linux 工具一样,Sed 支持正则表达式。本章将深入探讨 Sed 中使用的 regex 语法的复杂性。我们将涵盖 Sed 默认使用的基本正则表达式(Basic Regular Expressions,BRE),POSIX 字符类以及特殊的 GNU Sed 元字符。我们还将稍微提及扩展正则表达式(Extended Regular Expressions,ERE),它可以简化许多模式。
理解基本正则表达式与扩展正则表达式 (BRE vs. ERE)
Section titled “理解基本正则表达式与扩展正则表达式 (BRE vs. ERE)”Sed 默认使用基本正则表达式(BRE)。在 BRE 中,某些字符如 ?、+、{}、|、( 和 ) 失去了其特殊含义,必须用反斜杠转义(例如,\?、\+、\{\}、\|、\(\))。
大多数现代 Sed 版本(特别是 GNU Sed)通过命令行选项 -E 或 -r(对于 GNU Sed)支持扩展正则表达式(ERE)。在 ERE 中,这些字符无需反斜杠即可重新获得其特殊含义,从而使模式更清晰、更易读。本教程将主要使用 BRE 语法,因为它作为 Sed 的默认模式,但我们经常会指出 ERE 如何简化表达式。
核心正则表达式元字符 (BRE)
Section titled “核心正则表达式元字符 (BRE)”行首 (^)
Section titled “行首 (^)”脱字符号 (^) 匹配模式空间的开头(通常是文本行)。以下示例打印 books.txt 中所有以单词 “The” 开头的行。
[user]$ sed -n '/^The/p' books.txt假设 books.txt 包含:
- A Storm of Swords, J. R. R. Tolkien
- The Two Towers, J. R. R. Tolkien
- The Alchemist, Paulo Coelho
- The Fellowship of the Ring, J. R. R. Tolkien
- The Pilgrimage, Paulo Coelho
执行该命令得到:
2) The Two Towers, J. R. R. Tolkien3) The Alchemist, Paulo Coelho4) The Fellowship of the Ring, J. R. R. Tolkien5) The Pilgrimage, Paulo Coelho行尾 ($)
Section titled “行尾 ($)”美元符号 ($) 匹配模式空间的末尾。以下示例打印以 “Coelho” 结尾的行。
[user]$ sed -n '/Coelho$/p' books.txt执行该命令得到:
3) The Alchemist, Paulo Coelho5) The Pilgrimage, Paulo Coelho单个字符 (.)
Section titled “单个字符 (.)”点号 (.) 匹配除换行符外的任何单个字符。以下示例从输入流中打印以 ‘t’ 结尾的三个字母的单词。
[user]$ echo -e "cat\nbat\nrat\nmat\nbatting\nrats\nmats" | sed -n '/^..t$/p'执行该命令得到:
catbatratmat字符集 ([…])
Section titled “字符集 ([…])”方括号 [] 定义一个字符集,匹配集合中的任何单个字符。例如,/[CT]all/ 匹配 “Call” 或 “Tall”。
[user]$ echo -e "Call\nTall\nBall" | sed -n '/[CT]all/p'执行该命令得到:
CallTall排除型字符集 ([^…])
Section titled “排除型字符集 ([^…])”方括号内的第一个字符如果是脱字符 ^,则表示对集合取反,匹配 不 在该集合中的任何单个字符。/[^CT]all/ 匹配 “Ball”,但不匹配 “Call” 或 “Tall”。
[user]$ echo -e "Call\nTall\nBall" | sed -n '/[^CT]all/p'执行该命令得到:
Ball字符范围 ([-])
Section titled “字符范围 ([-])”字符集内的连字符 - 指定一个范围。/[C-Z]all/ 匹配从 C 到 Z 的任何大写字母后跟 “all”。
[user]$ echo -e "Call\nTall\nBall" | sed -n '/[C-Z]all/p'执行该命令得到:
CallTall修改范围为 /[A-P]all/ 会改变匹配结果:
[user]$ echo -e "Call\nTall\nBall" | sed -n '/[A-P]all/p'执行该命令得到:
CallBall量词 (重复)
Section titled “量词 (重复)”量词指定前面的字符或组可以出现的次数。记住在 BRE 中需要转义这些字符。
零次或一次出现 (?)
Section titled “零次或一次出现 (?)”转义的问号 \? 匹配前面的字符零次或一次出现。(在 ERE 中,使用 ?)。这使得该字符成为可选的。示例匹配 “Behaviour” 和 “Behavior”。
[user]$ echo -e "Behaviour\nBehavior" | sed -n '/Behaviou\?r/p'执行该命令得到:
BehaviourBehavior一次或多次出现 (+)
Section titled “一次或多次出现 (+)”转义的加号 \+ 匹配前面的字符一次或多次出现。(在 ERE 中,使用 +)。示例匹配包含一个或多个 ‘2’ 的行。
[user]$ echo -e "111\n22\n123\n234\n456\n222" | sed -n '/2\+/p'执行该命令得到:
22123234222零次或多次出现 (*)
Section titled “零次或多次出现 (*)”星号 * 匹配前面的字符零次或多次出现。(在 BRE 中用于此基本用法时不需要转义)。示例匹配 “ca”、“cat”、“catt” 等。
[user]$ echo -e "ca\ncat\ncaz" | sed -n '/cat*/p'执行该命令得到:
cacat恰好 N 次出现 ({N})
Section titled “恰好 N 次出现 ({N})”转义的花括号 \{N\} 恰好匹配前面的字符 N 次出现。(在 ERE 中,使用 {N})。示例只打印 numbers.txt 中的三位数字。
[user]$ cat numbers.txt110100100010000[user]$ sed -n '/^[0-9]\{3\}$/p' numbers.txt执行该命令得到:
100至少 N 次出现 ({N,})
Section titled “至少 N 次出现 ({N,})”\{N,\} 匹配至少 N 次出现。(在 ERE 中,使用 {N,})。示例打印五位或更多位数字的数字。
[user]$ sed -n '/^[0-9]\{5,\}$/p' numbers.txt执行该命令得到:
10000N 到 M 次出现 ({N,M})
Section titled “N 到 M 次出现 ({N,M})”\{N,M\} 匹配至少 N 次,最多 M 次出现。(在 ERE 中,使用 {N,M})。示例打印至少三位但不超过四位数字的数字。
[user]$ sed -n '/^[0-9]\{3,4\}$/p' numbers.txt执行该命令得到:
1001000交替 (|)
Section titled “交替 (|)”转义的管道符 \|(在转义的括号 \(...\) 内)充当逻辑或 (OR),匹配其左侧或右侧的表达式。(在 ERE 中,使用 | 和 (...))。示例匹配 “str1” 或 “str3”。
[user]$ echo -e "str1\nstr2\nstr3\nstr4" | sed -n '/str\(1\|3\)/p'执行该命令得到:
str1str3注意:对于复杂的交替或分组,强烈推荐使用 -E(或 -r)来使用扩展正则表达式以提高可读性:sed -E -n '/str(1|3)/p'。
转义特殊字符
Section titled “转义特殊字符”要匹配在 regex 中具有特殊含义的字符(如 .、*、[、$、^),您必须用反斜杠 \ 转义它们。例如,要匹配字面上的点,使用 \.)。一些序列如 \n(换行符)或 \t(制表符)表示不可打印字符,尽管它们在 Sed 模式中的解释可能很棘手,通常最好在 s 命令的替换部分使用它们或依靠 POSIX 字符类。
转义反斜杠 (\)
Section titled “转义反斜杠 (\)”要匹配字面上的反斜杠,您需要对其进行转义:\\。
[user]$ echo 'path\to\file' | sed -n '/to\\file/p'执行该命令得到:
path\to\file转义其他特殊字符(例如,\. 表示字面上的点)
Section titled “转义其他特殊字符(例如,\. 表示字面上的点)”要匹配字面上的点号(.),您必须将其转义为 \.)。否则,. 匹配任何字符。
[user]$ echo -e "file.txt\nfile_txt" | sed -n '/file\.txt/p'执行该命令得到:
file.txt表示不可打印字符 (ASCII 值)
Section titled “表示不可打印字符 (ASCII 值)”虽然 Sed 主要处理文本行,但某些版本(特别是 GNU Sed)允许按其 ASCII 值匹配字符。这不太常见,且通常与平台相关。
十进制 ASCII (\dNNN - GNU Sed)
\dNNN 按其十进制 ASCII 值 NNN 匹配字符。示例:\d97 代表 ‘a’。
[user]$ echo -e "a\nb\nc" | sed -n '/\d97/p' # GNU Sed specific执行该命令(使用 GNU Sed)得到:
a八进制 ASCII (\oNNN - GNU Sed)
\oNNN 按其八进制 ASCII 值 NNN 匹配字符。示例:\o142 代表 ‘b’。
[user]$ echo -e "a\nb\nc" | sed -n '/\o142/p' # GNU Sed specific执行该命令(使用 GNU Sed)得到:
b十六进制 ASCII (\xHH - GNU Sed)
\xHH 按其十六进制 ASCII 值 HH 匹配字符。示例:\x63 代表 ‘c’。
[user]$ echo -e "a\nb\nc" | sed -n '/\x63/p' # GNU Sed specific执行该命令(使用 GNU Sed)得到:
cPOSIX 字符类
Section titled “POSIX 字符类”POSIX 字符类是在字符集 [] 中用 [: 和 :] 包围的特殊关键字。它们提供了一种可移植的方式来匹配常见的字符类型,同时遵守区域设置。
[:alnum:] - 字母数字字符
Section titled “[:alnum:] - 字母数字字符”匹配字母和数字。示例:/[[:alnum:]]/ 匹配包含至少一个字母或数字的行。
[user]$ echo -e "One\n123\n@#\n\t" | sed -n '/[[:alnum:]]/p'执行该命令得到:
One123[:alpha:] - 字母字符
Section titled “[:alpha:] - 字母字符”只匹配字母。示例:/[[:alpha:]]/ 匹配包含至少一个字母的行。
[user]$ echo -e "One\n123\n@#\n\t" | sed -n '/[[:alpha:]]/p'执行该命令得到:
One[:blank:] - 空白字符
Section titled “[:blank:] - 空白字符”匹配空格和制表符。示例匹配只包含一个制表符的行。cat -vte 用于可视化不可打印字符(^I 代表制表符,$ 代表行尾)。
[user]$ echo -e "Word\n \n\t" | sed -n '/^[[:blank:]]\+$/p' | cat -vte执行该命令得到(只包含空格或制表符的行):
^I$[:digit:] - 数字
Section titled “[:digit:] - 数字”匹配十进制数字 (0-9)。在许多区域设置中等效于 [0-9])。示例:/[[:digit:]]/ 匹配包含至少一个数字的行。
[user]$ echo -e "abc\n123\n@#\n\t" | sed -n '/[[:digit:]]/p'执行该命令得到:
123[:lower:] - 小写字母
Section titled “[:lower:] - 小写字母”匹配小写字母。示例:/[[:lower:]]/ 匹配包含至少一个小写字母的行。
[user]$ echo -e "one\nTWO\n123\n\t" | sed -n '/[[:lower:]]/p'执行该命令得到:
one[:upper:] - 大写字母
Section titled “[:upper:] - 大写字母”匹配大写字母。示例:/[[:upper:]]/ 匹配包含至少一个大写字母的行。
[user]$ echo -e "one\nTWO\n123\n\t" | sed -n '/[[:upper:]]/p'执行该命令得到:
TWO[:punct:] - 标点符号
Section titled “[:punct:] - 标点符号”匹配标点符号(例如,.、,、;、!、?)。示例:/[[:punct:]]/ 匹配包含至少一个标点符号的行。
[user]$ echo -e "One,Two\nThree Four\nEnd!" | sed -n '/[[:punct:]]/p'执行该命令得到:
One,TwoEnd![:space:] - 空白字符
Section titled “[:space:] - 空白字符”匹配空白字符,包括空格、制表符、换行符、回车符、换页符和垂直制表符。以下示例使用 cat -vte 可视化包含空格、换页符 (^L) 和制表符 (^I) 的行。
[user]$ echo -e "Word\nLine with space \f\t" | sed -n '/[[:space:]]/p' | cat -vte执行该命令得到(所有输入行都匹配,因为它们包含空格或其他空白字符):
Word$Line with space ^L^I$GNU Sed 元字符 (类似 Perl)
Section titled “GNU Sed 元字符 (类似 Perl)”GNU Sed 提供附加的元字符,通常受 Perl 启发,可以简化常见的匹配任务。这些是 GNU 扩展,在其他 Sed 版本中可能不可用。使用这些元字符时,最好意识到潜在的移植性问题,或者如果需要严格遵守 POSIX 标准,则使用 --posix 选项。
单词边界 (\b)
Section titled “单词边界 (\b)”\b 匹配单词字符(即 [:alnum:] 加上 _)与非单词字符之间的零宽度边界,或者在行首/行尾(如果与单词字符相邻)。例如,\bthe\b 将 “the” 作为整个单词匹配,但不匹配 “these” 或 “other” 中的 “the”。
[user]$ echo -e "these\nthe theme\nthey\nthen" | sed -n '/\bthe\b/p'执行该命令得到:
the theme非单词边界 (\B)
Section titled “非单词边界 (\B)”\B 匹配一个 不是 单词边界的零宽度位置。例如,the\B 匹配 “the” 当它是 “these” 或 “they” 等更大单词的一部分时,但不匹配作为整个单词的 “the”。
[user]$ echo -e "these\nthe\nthey" | sed -n '/the\B/p'执行该命令得到:
thesethey空白字符 (\s)
Section titled “空白字符 (\s)”\s 匹配任何空白字符(等效于 [[:space:]])。示例匹配 “Line” 后跟任何空白字符。
[user]$ echo -e "Line\t1\nLine 2\nLine3" | sed -n '/Line\s/p'执行该命令得到:
Line\t1Line 2非空白字符 (\S)
Section titled “非空白字符 (\S)”\S 匹配任何非空白字符(与 \s 相反;等效于 [^[:space:]])。示例匹配 “Line” 后跟一个非空白字符。
[user]$ echo -e "Line\t1\nLine 2\nLine3" | sed -n '/Line\S/p'执行该命令得到:
Line3单词字符 (\w)
Section titled “单词字符 (\w)”\w 匹配任何单词字符(字母数字字符加上下划线:[[:alnum:]_])。
[user]$ echo -e "One\n123\n1_2\n&;#" | sed -n '/^\w\+$/p'执行该命令得到的行只包含单词字符:
One1231_2非单词字符 (\W)
Section titled “非单词字符 (\W)”\W 匹配任何非单词字符(与 \w 相反;[^[:alnum:]_])。
[user]$ echo -e "One\n123\n1_2\n&;#" | sed -n '/\W/p'执行该命令得到的行包含非单词字符:
1_2&;#模式空间开头 (`)
Section titled “模式空间开头 (`)”\``(反斜杠后引号)匹配模式空间的开头。这类似于 ^,但在某些高级多行场景下与 D 等命令的行为不同。对于大多数单行处理,^` 更常用且更具可移植性。
[user]$ echo -e "One\nTwo One" | sed -n '/\`One/p'执行该命令得到:
One模式空间末尾 (’)
Section titled “模式空间末尾 (’)”\'(反斜杠单引号)匹配模式空间的末尾。类似于 $,但在多行处理中有细微差别。对于单行处理,$ 是标准的。
[user]$ echo -e "End Note\nNote" | sed -n '/Note\'/p'执行该命令得到:
End NoteNote进一步学习:要获取更多关于正则表达式的深入信息,请查阅您系统上的 regex(7) man 手册页或在线资源,例如 regex101.com(选择 PCRE/Perl 风格可获得与 GNU 扩展类似的模式,或选择 POSIX ERE/BRE 获得标准 Sed 模式)。