高级 shell 脚本中的正则表达式使用指南
1. 高级 shell 脚本数据处理概述
在 shell 脚本中,虽然它自身可以完成很多工作,但仅靠 shell 脚本处理数据往往存在困难。Linux 提供了两个实用工具来辅助处理文本数据:
-
sed 编辑器
:它是一种流编辑器,能在读取数据时快速对其进行处理。使用时需为 sed 编辑器提供一系列编辑命令,它会将这些命令应用到数据上。
-
gawk 程序
:这是 GNU 组织开发的工具,模仿并扩展了 Unix awk 程序的功能。gawk 程序内置了一种编程语言,可用于编写处理和加工数据的脚本。它能从大型数据文件中提取数据元素,并以任意所需格式输出,这使得处理大型日志文件变得轻松,还能根据数据文件生成自定义报告。
而使用 sed 和 gawk 程序的关键在于掌握正则表达式的运用,正则表达式是创建自定义过滤器以提取和操作文本文件中数据的关键。
2. 正则表达式基础
2.1 正则表达式定义
正则表达式是用户定义的模式模板,Linux 实用工具(如 sed 或 gawk)会用它来过滤文本。当数据流入这些工具时,它们会将正则表达式模式与数据进行匹配。若数据与模式匹配,则接受该数据进行处理;若不匹配,则拒绝该数据。正则表达式模式利用通配符来表示数据流中的一个或多个字符。例如,在 Linux 中使用
ls
命令列出文件和目录时,就可以使用通配符:
$ ls -al da*
-rw-r--r-- 1 rich rich 45 Nov 26 12:42 data
-rw-r--r-- 1 rich rich 25 Dec 4 12:40 data.tst
-rw-r--r-- 1 rich rich 180 Nov 26 12:42 data1
-rw-r--r-- 1 rich rich 45 Nov 26 12:44 data2
-rw-r--r-- 1 rich rich 73 Nov 27 12:31 data3
-rw-r--r-- 1 rich rich 79 Nov 28 14:01 data4
-rw-r--r-- 1 rich rich 187 Dec 4 09:45 datatest
da*
参数指示
ls
命令仅列出文件名以 “da” 开头的文件,“da” 后面可以有任意数量的字符(包括没有)。
正则表达式的通配符模式工作方式类似,它包含文本和/或特殊字符,为 sed 和 gawk 在匹配数据时提供模板。可以使用不同的特殊字符在正则表达式中定义特定的过滤模式。
2.2 正则表达式类型
在 Linux 环境中,不同的应用程序使用不同类型的正则表达式,主要的正则表达式引擎有:
-
POSIX 基本正则表达式(BRE)引擎
:大多数 Linux 实用工具至少遵循 POSIX BRE 引擎规范,能识别其定义的所有模式符号。不过,有些工具(如 sed)仅遵循 BRE 引擎规范的一个子集,这是出于速度考虑,因为 sed 要尽可能快地处理数据流中的文本。
-
POSIX 扩展正则表达式(ERE)引擎
:常用于依赖正则表达式进行文本过滤的编程语言中,它提供了高级模式符号以及用于常见模式(如匹配数字、单词和字母数字字符)的特殊符号。gawk 使用 ERE 引擎处理其正则表达式模式。
3. 定义 BRE 模式
3.1 纯文本匹配
正则表达式可以使用标准文本字符串来过滤数据,示例如下:
$ echo "This is a test" | sed -n '/test/p'
This is a test
$ echo "This is a test" | sed -n '/trial/p'
$
$ echo "This is a test" | gawk '/test/{print $0}'
This is a test
$ echo "This is a test" | gawk '/trial/{print $0}'
$
从上述示例可以看出:
- 正则表达式不关心模式在数据流中的位置,也不关心模式出现的次数,只要能在文本字符串中匹配到模式,就会将字符串传递给使用它的 Linux 实用工具。
- 正则表达式对模式匹配非常严格,区分大小写。例如:
$ echo "This is a test" | sed -n '/this/p'
$
$ echo "This is a test" | sed -n '/This/p'
This is a test
$
- 正则表达式不限于匹配完整的单词,只要定义的文本出现在数据流中,就会匹配。但如果尝试匹配的完整文本未出现在数据流中,则匹配失败。例如:
$ echo "The books are expensive" | sed -n '/book/p'
The books are expensive
$
$ echo "The book is expensive" | sed -n '/books/p'
$
- 正则表达式中可以包含空格和数字,空格与其他字符一样对待。例如:
$ echo "This is line number 1" | sed -n '/ber 1/p'
This is line number 1
$
$ echo "This is line number1" | sed -n '/ber 1/p'
$
还可以创建匹配多个连续空格的正则表达式模式:
$ cat data1
This is a normal line of text.
This is a line with too many spaces.
$ sed -n '/ /p' data1
This is a line with too many spaces.
$
3.2 特殊字符处理
正则表达式为一些字符赋予了特殊含义,如果在文本模式中直接使用这些字符,可能无法得到预期结果。这些特殊字符包括:
.*[]^${}\+?|()
。
若要将特殊字符用作普通文本字符,需要对其进行转义,即在其前面添加反斜杠字符
\
。例如,搜索文本中的美元符号:
$ cat data2
The cost is $4.00
$ sed -n '/\$/p' data2
The cost is $4.00
$
由于反斜杠本身也是特殊字符,若要在正则表达式模式中使用它,需要进行双重转义:
$ echo "\ is a special character" | sed -n '/\\/p'
\ is a special character
$
此外,虽然正斜杠不是正则表达式的特殊字符,但在 sed 或 gawk 的正则表达式模式中使用时会报错,也需要进行转义:
$ echo "3 / 2" | sed -n '///p'
sed: -e expression #1, char 2: No previous regular expression
$
$ echo "3 / 2" | sed -n '/\//p'
3 / 2
$
3.3 锚定字符使用
默认情况下,指定的正则表达式模式只要出现在数据流中的任何位置都会匹配。可以使用两个特殊字符将模式锚定到数据流中每行的开头或结尾:
-
从开头匹配
:使用脱字符
^
定义从每行文本开头开始的模式。若模式不在行首,正则表达式模式匹配失败。例如:
$ echo "The book store" | sed -n '/^book/p'
$
$ echo "Books are great" | sed -n '/^Book/p'
Books are great
$
脱字符锚定字符会根据换行符检查每个新行开头的模式:
$ cat data3
This is a test line.
this is another test line.
A line that tests this feature.
Yet more testing of this
$ sed -n '/^this/p' data3
this is another test line.
$
若脱字符不在模式开头,则它作为普通字符处理:
$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test
$
-
从结尾匹配
:美元符号
$特殊字符定义结尾锚定,将其添加到文本模式后,表示数据行必须以该文本模式结尾。例如:
$ echo "This is a good book" | sed -n '/book$/p'
This is a good book
$ echo "This book is good" | sed -n '/book$/p'
$
需要注意,使用结尾文本模式时要谨慎,确保匹配的内容符合预期。例如:
$ echo "There are a lot of good books" | sed -n '/book$/p'
$
- 组合锚定 :在某些情况下,可以同时使用开头和结尾锚定。例如,查找只包含特定文本模式的行:
$ cat data4
this is a test of using both anchors
I said this is a test
this is a test
I'm sure this is a test.
$ sed -n '/^this is a test$/p' data4
this is a test
$
还可以通过组合两个锚定且不包含文本的模式,过滤数据流中的空白行:
$ cat data5
This is one test line.
This is another test line.
$ sed '/^$/d' data5
This is one test line.
This is another test line.
$
3.4 点字符匹配
点特殊字符用于匹配除换行符之外的任何单个字符,但该位置必须有字符,否则模式匹配失败。示例如下:
$ cat data6
This is a test of a line.
The cat is sleeping.
That is a very nice hat.
This test is at line four.
at ten o'clock we'll go home.
$ sed -n '/.at/p' data6
The cat is sleeping.
That is a very nice hat.
This test is at line four.
$
3.5 字符类匹配
若要限制匹配的字符,可以使用字符类。通过方括号定义字符类,方括号内包含要包含在类中的任何字符,然后在模式中像使用其他通配符一样使用整个类。示例如下:
$ sed -n '/[ch]at/p' data6
The cat is sleeping.
That is a very nice hat.
$
字符类在不确定字符大小写时很有用,例如:
$ echo "Yes" | sed -n '/[Yy]es/p'
Yes
$ echo "yes" | sed -n '/[Yy]es/p'
yes
$
还可以在单个表达式中使用多个字符类:
$ echo "Yes" | sed -n '/[Yy][Ee][Ss]/p'
Yes
$ echo "yEs" | sed -n '/[Yy][Ee][Ss]/p'
yEs
$ echo "yeS" | sed -n '/[Yy][Ee][Ss]/p'
yeS
$
字符类不限于字母,也可以包含数字。例如:
$ cat data7
This line doesn't contain a number.
This line has 1 number on it.
This line a number 2 on it.
This line has a number 4 on it.
$ sed -n '/[0123]/p' data7
This line has 1 number on it.
This line a number 2 on it.
$
可以组合字符类来检查格式正确的数字,但在匹配特定格式时需谨慎。例如匹配邮政编码时:
$ cat data8
60633
46201
223001
4353
22203
$ sed -n '
>/[0123456789][0123456789][0123456789][0123456789][0123456789]/p
>' data8
60633
46201
223001
22203
$
这个例子虽然过滤掉了太短的数字,但仍通过了六位数的数字,因为正则表达式模式可以在数据流文本的任何位置找到,可能存在除匹配模式之外的其他字符。
以下是一个简单的 mermaid 流程图,展示正则表达式匹配数据的基本流程:
graph TD;
A[数据流入] --> B{匹配正则表达式模式};
B -- 匹配 --> C[接受处理];
B -- 不匹配 --> D[拒绝];
总结
本文介绍了在高级 shell 脚本中使用 sed 和 gawk 时正则表达式的重要性,详细阐述了正则表达式的定义、类型,以及如何定义 BRE 模式,包括纯文本匹配、特殊字符处理、锚定字符使用、点字符匹配和字符类匹配等内容。通过这些知识和示例,能帮助读者更好地掌握正则表达式在数据处理中的应用。
高级 shell 脚本中的正则表达式使用指南(续)
4. 扩展正则表达式(ERE)简介
虽然前面重点介绍了 BRE 模式,但 ERE 模式在处理更复杂的文本匹配时具有更大的优势。ERE 引擎提供了比 BRE 更丰富的特殊字符和功能,能让正则表达式更加灵活和强大。
4.1 ERE 特殊字符
ERE 引入了一些新的特殊字符,下面是一些常见的特殊字符及其功能:
| 特殊字符 | 功能描述 |
| ---- | ---- |
|
+
| 匹配前面的元素一次或多次。例如,
ab+
可以匹配
ab
、
abb
、
abbb
等,但不能匹配
a
。 |
|
?
| 匹配前面的元素零次或一次。例如,
ab?
可以匹配
a
或
ab
。 |
|
\|
| 用于表示或关系。例如,
a\|b
可以匹配
a
或者
b
。 |
|
()
| 用于分组。例如,
(ab)+
表示
ab
这个组合可以重复一次或多次。 |
下面是一些使用 ERE 特殊字符的示例:
# 使用 + 特殊字符
$ echo "abbb" | gawk --re-interval '/ab+/ {print $0}'
abbb
$ echo "a" | gawk --re-interval '/ab+/ {print $0}'
$
# 使用 ? 特殊字符
$ echo "a" | gawk --re-interval '/ab?/ {print $0}'
a
$ echo "ab" | gawk --re-interval '/ab?/ {print $0}'
ab
# 使用 | 特殊字符
$ echo "a" | gawk --re-interval '/a|b/ {print $0}'
a
$ echo "b" | gawk --re-interval '/a|b/ {print $0}'
b
# 使用 () 特殊字符
$ echo "abab" | gawk --re-interval '/(ab)+/ {print $0}'
abab
4.2 ERE 与 BRE 的对比
虽然 ERE 是在 BRE 的基础上扩展而来,但它们之间还是存在一些差异,下面通过表格进行对比:
| 对比项 | BRE | ERE |
| ---- | ---- | ---- |
| 特殊字符功能 | 相对较少,功能有限 | 提供更多高级特殊字符,功能更强大 |
| 使用场景 | 适用于简单的文本匹配 | 适用于复杂的文本匹配和处理 |
| 性能 | 处理速度可能相对较快,因为功能简单 | 由于功能复杂,处理速度可能稍慢 |
5. 正则表达式在实际场景中的应用
正则表达式在实际的数据处理和文本过滤中有广泛的应用,下面介绍一些常见的应用场景。
5.1 日志文件分析
在处理日志文件时,经常需要从大量的日志信息中提取特定的数据。例如,从服务器日志中提取所有的错误信息。假设日志文件
server.log
内容如下:
[2024-01-01 10:00:00] INFO: Server started.
[2024-01-01 10:01:00] ERROR: Database connection failed.
[2024-01-01 10:02:00] INFO: User logged in.
[2024-01-01 10:03:00] ERROR: File not found.
可以使用以下命令提取所有的错误信息:
$ cat server.log | gawk '/ERROR/ {print $0}'
[2024-01-01 10:01:00] ERROR: Database connection failed.
[2024-01-01 10:03:00] ERROR: File not found.
5.2 数据清洗
在处理数据时,可能会遇到一些格式不规范的数据,需要使用正则表达式进行清洗。例如,从一个包含电话号码的文件中提取所有合法的手机号码。假设文件
phone_numbers.txt
内容如下:
John: 13800138000
Jane: +86 13900139000
Tom: 12345678901 (invalid)
可以使用以下命令提取所有合法的手机号码:
$ cat phone_numbers.txt | gawk '/[1][3-9][0-9]{9}/ {print $2}'
13800138000
13900139000
5.3 表单验证
在编写脚本时,可能需要对用户输入的数据进行验证。例如,验证用户输入的邮箱地址是否合法。以下是一个简单的验证邮箱地址的示例:
#!/bin/bash
email="test@example.com"
if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Valid email address."
else
echo "Invalid email address."
fi
6. 正则表达式的优化与注意事项
在使用正则表达式时,为了提高匹配效率和避免错误,需要注意以下几点:
6.1 性能优化
-
避免过度使用贪婪匹配
:贪婪匹配会尽可能多地匹配字符,可能会导致性能下降。例如,
.*会匹配尽可能多的字符,在某些情况下可以使用非贪婪匹配.*?来提高性能。 - 合理使用分组 :分组可以让正则表达式更加清晰,但过多的分组会增加匹配的复杂度。在不需要分组的情况下,尽量避免使用。
6.2 错误处理
-
转义特殊字符
:在使用正则表达式时,要注意特殊字符的转义。如果需要匹配特殊字符本身,需要在前面加上反斜杠
\。 - 测试正则表达式 :在实际使用正则表达式之前,最好先进行测试,确保它能正确匹配预期的文本。可以使用一些在线正则表达式测试工具来进行测试。
以下是一个 mermaid 流程图,展示正则表达式优化的基本流程:
graph TD;
A[编写正则表达式] --> B{测试匹配结果};
B -- 匹配正确 --> C[使用正则表达式];
B -- 匹配错误 --> D{是否存在贪婪匹配或过多分组};
D -- 是 --> E[优化正则表达式];
D -- 否 --> F{是否需要转义特殊字符};
F -- 是 --> G[转义特殊字符];
F -- 否 --> H[检查其他错误];
E --> B;
G --> B;
H --> B;
7. 总结与展望
正则表达式是高级 shell 脚本中处理文本数据的强大工具。通过掌握正则表达式的基本概念、BRE 模式和 ERE 模式,以及如何在实际场景中应用正则表达式,能让我们更高效地处理和分析文本数据。
在未来的学习和工作中,可以进一步探索正则表达式的高级应用,如使用正则表达式进行数据挖掘、自然语言处理等。同时,随着技术的不断发展,正则表达式的功能也可能会不断扩展和完善,我们需要持续关注和学习。
希望本文能帮助你更好地理解和使用正则表达式,在实际应用中发挥出它的最大价值。
超级会员免费看
1330

被折叠的 条评论
为什么被折叠?



