sed 正则表达式

正则表达式是非常强大的功能,有了正则表达式,很多很复杂的问题就迎刃而解了。

比如我们从 price: 3.14$ 中查找价格,没有正则表达式, 我们不得不遍历所有字符,判断是否是数字和小数点。有了正则表达式,我们只需要使用 \d+\.?\d* 就可以了。

sed 之所以那么早出名,也得益于它早早的就支持正则表达式了。

sed 的正则表达式非常强大,尤其是 GNU SED 这个版本,除了能够使用标准正则表达式,还支持 POSIX 类等正则表达式扩展。

今天,我们开始学习 sed 中的正则表达式。

标准正则表达式元字符

匹配行首 (^)

插入符号( ^ ) 是标准正则表达式中的一个元字符,表示从一行的开头开始匹配。

例如 ^小明 只会匹配那些以 小明 开始的行。

范例

我们现在当前目录下新建一个文件 student.txt,内容如下

小明,23岁,北京大学
小红,22岁,清华大学
小李,25岁,斯坦福大学
小王,22岁,清华大学

然后我们再测试 ^小明 是否只会匹配那些以 小明 开始的行。

[www.twle.cn]$ sed -n '/^小明/ p' student.txt

运行结果如下

小明,23岁,北京大学

匹配行尾 ($)

美元符号( $ ) 是表示从一行必须以 $ 符号前的文本结束。

例如 清华大学$ 只会匹配那些以 清华大学 结束的行。

范例

我们现在当前目录下新建一个文件 student.txt,内容如下

小明,23岁,北京大学
小红,22岁,清华大学
小李,25岁,斯坦福大学
小王,22岁,清华大学

然后我们再测试 清华大学$ 只会匹配那些以 清华大学 结束的行。

[www.twle.cn]$ sed -n '/清华大学$/ p' student.txt

运行结果如下

小红,22岁,清华大学
小王,22岁,清华大学

匹配任意单个字符(.)

点号( . ) 是匹配任意单个非换行符的字符。也就是说是什么无所谓,但数量只能是 1 个。

例如 .at 匹配 batcatmat 等等,但是不能匹配 atccat

[www.twle.cn]$ echo -e "cat\nbat\nrat\nmat\nbatting\nrats\nmats" | sed -n '/^.at$/p'

运行结果如下

cat
bat
rat
mat

匹配任意存在字符列表中的一个字符( [] )

标准的正则表达式使用 方括号 [] 表示字符列表,俗称字符集。

字符列表 [] 用于匹配任意 存在 [] 里的字符。

例如 [CT] 可以匹配单个 CT ,但是不能匹配其它字符,也不能匹配 CT

[www.twle.cn]$ echo -e "Call\nTall\nBall" | sed -n '/[CT]all/ p'

运行结果如下

Call
Tall

匹配任意不在字符列表中的一个字符 ( [^] )

标准的正则表达式使用 方括号 [] 表示字符列表,俗称字符集。

字符列表 [^] 用于匹配任意 不存在 [^] 里的字符。

^ 本身除外,如果不需要匹配 ^ 则需要重复输入 ^

例如 [^CT] 可以任意单个字符,除了 CT

[www.twle.cn]$ echo -e "Call\nTall\nBall" | sed -n '/[^CT]all/ p'

运行结果如下

Ball

匹配连续范围的字符 ( [-] )

所谓 连续范围的字符,就是按照 ASCII 表中出现的先后顺序排列的字符列表。

标准的正则表达式使用 破号 也就是 中划线( - 来表示连续范围的字符。

- 左边的字符表示开始,- 左边的字符表示结束。

例如 0-9 表示 0123456789,例如 a-e 表示 abcde

标准的正则表达式使用 方括号 [] 表示字符列表,俗称字符集。

因此 [-] 用于匹配任意 存在 连续范围的字符集 [] 里的字符。

例如 [C-Z] 表示任意单个存在字符列表 [CDEFGHIJKLMNOPQRSTUVWXYZ] 里的字符。

[www.twle.cn]$ echo -e "Call\nTall\nBall" | sed -n '/[C-Z]all/ p'

运行结果如下

Call 
Tall

如果我们将连续字符集改为 A-P

[jerry]$ echo -e "Call\nTall\nBall" | sed -n '/[A-P]all/ p'

运行结果如下

Call 
Ball

只出现 0 次或 1 次 ( \? )

标准的正则表达式使用 问号(? 表示前面的字符只出现 0 次或 1 次。

但是,因为 sed 将 ? 当作了普通字符,所以使用 \? 来表示前面的字符只出现 0 次或 1 次。

苹果电脑自带的 sed 不支持 \?

例如 Pea\?r 可以匹配 PerPear,但不能匹配 Peaar

[www.twle.cn]$ echo -e "Pear\nPeaar\nPer" | sed -n '/Pea\?r/ p'

运行结果如下

Pear
Per

至少出现一次 ( \+ )

标准的正则表达式使用 加号(+ 表示前面的字符需要出现至少一次。

因为 sed 将 + 当作了普通字符,所以使用 \+ 来表示前面的字符需要出现至少一次。

苹果电脑自带的 sed 不支持 \+

例如 Pea\+r 可以匹配 PearPeaar,但不能匹配 Per

[www.twle.cn]$ echo -e "Pear\nPeaar\nPer" | sed -n '/Pea\+r/ p'

运行结果如下

Pear
Peaar

出现任意次数 (*)

标准的正则表达式使用 星号(* 表示前面的字符可以出现任意次数。也就是可以出现 0 次或 1 次或更多次数。

例如 ca*t 可以匹配 ctcatcaat 等等。

[www.twle.cn]$ echo -e "ct\nca\ncat\ncaat" | sed -n '/ca*t/ p'

运行结果如下

ct
cat
caat

精确出现 n 次 ( {n} )

标准的正则表达式使用 {n} 表示前面的字符需要精确出现 n 次。

因为 sed 将 {n} 当作了普通字符,所以使用 \{n\} 来表示前面的字符需要精确出现 n 次。

例如 ^8\{3\}$ 只能匹配 888 而不能匹配 888888

[www.twle.cn]$ echo -e "8\n88\n888\n8888" | sed -n '/^8\{3\}$/ p'

运行结果如下

888

至少出现 n 次 ( {n,}

标准的正则表达式使用 {n,} 表示前面的字符需要至少出现 n 次。

因为 sed 将 {} 当作了普通字符,所以使用 \{n,\} 来表示前面的字符需要至少出现 n 次。

例如 ^8\{3,\}$ 可以匹配 8888888 但不能匹配 88

[www.twle.cn]$ echo -e "8\n88\n888\n8888" | sed -n '/^8\{3,\}$/ p'

运行结果如下

888
8888

出现 M 到 N 次

{m, n} 用于表示前面字符的至少出现 m 次,最多出现 n 次。

因为 sed 将 {} 当作了普通字符,所以使用 \{m,n\} 来表示前面字符的至少出现 m 次,最多出现 n 次。

例如 ^8{2,4}$ 可以匹配 888888888 但是不会匹配 888888

[www.twle.cn]$ echo -e "8\n88\n888\n8888\n88888" | sed -n '/^8\{3,\}$/ p'

运行结果如下

888
8888
88888

管道符 (|)

竖线| 又称 管道符,在所有的正则表达式中都有着特殊的意义。它用于表示 的意思。

管道符通常和 小括号 () 一起使用,用于从两个选择中匹配一个即可。

苹果电脑自带的 sed 不支持管道符 (|)。

例如正则表达式 /str\(1\|3\)/ 既可以匹配 str1 也可以匹配 str3

[www.twle.cn]$ echo -e "str1\nstr2\nstr3\nstr4" | sed -n '/str\(1\|3\)/ p'

运行结果如下

str1 
str3

注意: 管道符和小括号需要使用 \ 转义。

正则表达式转义字符

正则表达式中还有一类特殊意义的字符,它们通常由 正斜杠(\ 和小写字母组合而成。

例如,新行使用 \n 表示,回车使用 \r 表示等等等等。我们称这些字符为 转义字符

sed 的正则表达式匹配这些特殊意义的转义字符需要再转义一次,也就是在前面在添加一个 正斜杠(\

例如 \n 改成 \\n\r 改成 \\r

本小节,我们开始学习 sed 中支持的那些转义字符。

正斜杠 "\"

因为 正斜杠 "\" 和其它任意字母组合在一起都有一个特殊意思,就是转义这个字母。

因此如果要匹配 正斜杠 "\" ,则需要在前面额外添加一个 正斜杠 "\"

[www.twle.cn]$ echo 'str1\str2' | sed -n '/\\/ p'

运行结果如下

str1\str2

换行符 "\n"

\n 用于表示 换行符

如果要匹配两个字母 \n ,那么在使用的时候需要额外添加一个 正斜杠(\

[www.twle.cn]$ echo 'str1\nstr2' | sed -n '/\\n/ p'

运行结果如下

str1\nstr2

回车符 "\r"

\r 用于表示 回车符

如果要匹配两个字母 \r ,那么在使用的时候需要额外添加一个 正斜杠(\

[www.twle.cn]$ echo 'str1\rstr2' | sed -n '/\\r/ p'

运行结果如下

str1\rstr2

十进制字符 "\dnnn"

\dnnn 用于表示十进制字符 nnn

苹果电脑自带的 sed 不支持 \dnnn

例如 \d97 用于表示字母 a,查 ASCII 表可得数字 97 表示字母 a

[www.twle.cn]$ echo -e "a\nb\nc" | sed -n '/\d97/ p'

运行结果如下

a

八进制 "\onnn"

\onnn 用于表示八进制字符 nnn

o 是字母 opq 中的 o 而不是数字 0

苹果电脑自带的 sed 不支持 \onnn

例如 \o142 用于表示字符 b\o142 转换为十进制就是 98,查 ASCII 表可得字母 b

[www.twle.cn]$ echo -e "a\nb\nc" | sed -n '/\o142/ p'

运行结果如下

b

十六进制 "\xnnn"

\xnnn 用于表示十六进制字符 nnn

苹果电脑自带的 sed 不支持 \xnnn

例如 \x64 用于表示字符 c\o63 转换为十进制就是 99,查 ASCII 表可得字母 c

[www.twle.cn]$ echo -e "a\nb\nc" | sed -n '/\x63/ p'

运行结果如下

c

POSIX 正则表达式

sed 支持 POSIX 规范下的正则表达式。

POSIX 正则表达式有个特点,就是支持一些具有特殊含义的 保留词

这些特殊的 保留词 在 POSIX 中被称为 POSIX 类

接下来的一小节,我们就来了解下 sed 支持的 POSIX 类。

字母数字 [:alnum:]

[:alnum:] 用于表示任意单个大小写字母 a-zA-Z 或单个数字 0-9

用上面所学的知识,[[:alnum:]] 其实就是 [0-9a-zA-Z]

例如 [[:alnum:]] 可以匹配 One123 但是不能比配 \t

[www.twle.cn]$ echo -e "One\n123\n\t" | sed -n '/[[:alnum:]]/ p'

运行结果如下

One 
123

字母 [:alpha:]

[:alpha:] 用于表示任意单个大小写字母 a-zA-Z

用上面所学的知识,[[:alpha:]] 其实就是 [a-zA-Z]

例如 [[:alpha:]] 可以匹配 One 但是不能匹配 123\t

[www.twle.cn]$ echo -e "One\n123\n\t" | sed -n '/[[:alpha:]]/ p'

运行结果如下

One

空白符 [:blank:]

[:blank:] 用于表示任意单个空格 ' ' 或制表符 \t

例如 [:blank:] 可以匹配 \t 但是不会匹配 One123

[www.twle.cn]$ echo -e "One\n123\n\t" | sed -n '/[[:space:]]/ p' | cat -vte

运行结果如下

^I$

注意, 命令 cat -vte 会将制表符 \t 显示为 ^I

数字 [:digit:]

[:digit:] 用于表示任意单个数字 0-9

用上面所学的知识,[[:digit:]] 其实就是 [0-9]

例如 [[:digit:]] 可以匹配 123 但是不能匹配 One\t

[www.twle.cn]$ echo -e "abc\n123\n\t" | sed -n '/[[:digit:]]/ p'

运行结果如下

123

小写字母 [:lower:]

[:lower:] 用于表示任意单个小写字母 a-z

用上面所学的知识,[[:lower:]] 其实就是 [a-z]

例如 [[:lower:]] 可以匹配 one 但是不能匹配 TWO\t

[www.twle.cn]$ echo -e "one\nTWO\n\t" | sed -n '/[[:lower:]]/ p'

运行结果如下

one

大写字母 [:upper:]

[:upper:] 用于表示任意单个大写字母 A-Z

用上面所学的知识,[[:upper:]] 其实就是 [A-Z]

例如 [[:upper:]] 可以匹配 TWO 但是不能匹配 one\t

[www.twle.cn]$ echo -e "one\nTWO\n\t" | sed -n '/[[:upper:]]/ p'

运行结果如下

TWO

标点符号 [:punct:]

[:punct:] 用于表示任意单个标点符号。

例如 [:punct:] 可以匹配 One,123 但是不匹配 Three123

[www.twle.cn]$ echo -e "One,Two\nThree\n123" | sed -n '/[[:punct:]]/ p'

运行结果如下

One,Two

空白符 [:space:]

[:space:] 用于表示任意单个空白符。

ASCII 编码中,空白符包含 空格(' ')制表符('\t')回车符('\r')换行符('\n')垂直制表符('\v')换页符('\F')

例如 [:blank:] 可以匹配 \t\f 但是不会匹配 One

[www.twle.cn]$ echo -e "One\n123\f\n456\t" | sed -n '/[[:space:]]/ p' | cat -vte

输出结果如下

123^L$
456^I$

正则表达式元字符

跟其它语言的正则表达式一样,SED 同样支持正则表达式元字符。

元字符 通常由 正斜杠(\ 和 一个字母组合而成。它们是一体的,放在一起表示单个字符而不是两个字符。 这也是元字符的由来。

sed 所支持的正则表达式元字符,是从 Perl 借鉴过来的。

需要注意,元字符几乎只有 GNU SED 支持,其它的 SED 变体可能就不支持了。比如苹果电脑自带的 sed 就不支持。

下面,我们开始简单的介绍下几个会经常用到的元字符。

单词边界 \b

在正则表达式中,\b 并不表示 回退,而是表示 单词边界

苹果电脑自带的 sed 不支持 \b

那什么是单词边界呢?

单词边界就是一个单词和另一个单词的区分标志,通常是 空格换行 等。

例如 /\bthe\b/ 可以匹配 the 但是不能匹配 thesethere, they, then 等等。

[www.twle.cn]$ echo -e "these\nthe\nthey\nthen" | sed -n '/\bthe\b/ p'

运行结果如下

the

非单词边界 \B

\B\b 的作用正好相反,用于匹配非单词边界。

那什么是单词边界呢?

单词边界就是一个单词和另一个单词的区分标志,通常是 空格换行 等。

例如 /the\B/ 可以匹配 thesethey 但是不能匹配 the

[www.twle.cn]$ echo -e "these\nthe\nthey" | sed -n '/the\B/ p'

运行结果如下

these
they

单个空白符 \s

\s 用于匹配单个空白符。

ASCII 编码中,空白字符包含 空格(' ')制表符('\t')回车符('\r')换行符('\n')垂直制表符('\v')换页符('\F')

苹果电脑自带的 sed 不支持 \s

例如 /Line\s/ 可以匹配 Line\t,但是不会匹配 Line2

[www.twle.cn]$ echo -e "Line\t\nLine2" | sed -n '/Line\s/ p'

运行结果如下

Line

单个非空格 \S

\S 用于匹配单个非空白符。

ASCII 编码中,空白字符包含 空格(' ')制表符('\t')回车符('\r')换行符('\n')垂直制表符('\v')换页符('\F')

苹果电脑自带的 sed 不支持 \S

例如 /Line\S/ 可以匹配 Line2 但是不会匹配 Line\t

[www.twle.cn]$ echo -e "Line\t1\nLine2" | sed -n '/Line\S/ p'

运行结果如下

Line2

单个字符 \w

\w 用于匹配单个字符。

并不是所有的字符都可以被匹配的,ASCII 编码中只有 数字 0-9大小写字母下划线 三种类型的字符才能被 \w 匹配到。

苹果电脑自带的 sed 不支持 \w

例如下面的命令

[www.twle.cn]$ echo -e "一\nOne\n123\n1_2\n&;#" | sed -n '/\w/ p'

运行结果如下

一
One
123
1_2

单个非字符 \W

从上面的学习中,我们知道 \w 用于匹配单个字符:数字 0-9大小写字母下划线

\W 则是匹配 \w 之外的单个字符,也就是不包含在 数字 0-9大小写字母下划线 中的其它 ASCII 单个字符。

苹果电脑自带的 sed 不支持 \W

例如下面的命令

[www.twle.cn]$ echo -e "一\nOne\n123\n1_2\n&;#" | sed -n '/\W/ p'

运行结果如下

&;#

模式空间开始 ( '`' )

sed 提供了特殊字符 反引号(`)用于表示 模式空间 的开始。

` 是英文输入法状态下数字键 1 左边的那个键。

苹果电脑自带的 sed 不支持该特殊字符。

例如下面的 sed 命令

[www.twle.cn]$ echo -e "一二\n三\n一" | sed -n '/\`一/ p'

运行结果如下

一二
一
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.