- Unix / Linux 初学者
- Unix / Linux - 主页
- Unix / Linux - 入门
- Unix / Linux - 文件管理
- Unix / Linux - 目录
- Unix / Linux - 文件权限
- Unix / Linux - 环境
- Unix / Linux - 基本实用程序
- Unix / Linux - 管道和过滤器
- Unix / Linux - 进程
- Unix / Linux - 通信
- Unix / Linux - vi 编辑器
- Unix/Linux Shell 编程
- Unix / Linux - Shell 脚本
- Unix / Linux - 什么是 Shell?
- Unix / Linux - 使用变量
- Unix / Linux - 特殊变量
- Unix / Linux - 使用数组
- Unix / Linux - 基本运算符
- Unix / Linux - 决策
- Unix / Linux - Shell 循环
- Unix / Linux - 循环控制
- Unix / Linux - Shell 替换
- Unix / Linux - 引用机制
- Unix / Linux - IO 重定向
- Unix / Linux - Shell 函数
- Unix / Linux - 联机帮助页
Unix / Linux - 使用 SED 的正则表达式
在本章中,我们将详细讨论 Unix 中使用 SED 的正则表达式。
正则表达式是一个可用于描述多个字符序列的字符串。正则表达式由多种不同的 Unix 命令使用,包括ed、sed、awk、grep,以及在更有限的范围内的vi。
这里SED代表流编辑器。这个面向流的编辑器是专门为执行脚本而创建的。因此,您输入的所有输入都会通过并进入 STDOUT,并且不会更改输入文件。
调用 sed
在开始之前,让我们确保我们有/etc/passwd文本文件的本地副本来使用sed。
如前所述,可以通过管道向 sed 发送数据来调用它,如下所示 -
$ cat /etc/passwd | sed Usage: sed [OPTION]... {script-other-script} [input-file]... -n, --quiet, --silent suppress automatic printing of pattern space -e script, --expression = script ...............................
cat命令通过管道将/etc/passwd的内容转储到sed的模式空间中。模式空间是 sed 用于其操作的内部工作缓冲区。
sed 通用语法
以下是 sed 的一般语法 -
/pattern/action
这里,pattern是正则表达式,action是下表中给出的命令之一。如果省略模式,则会对每一行执行操作,如我们上面所见。
模式周围的斜杠字符 (/) 是必需的,因为它们用作分隔符。
先生。 | 范围和描述 |
---|---|
1 |
p 打印该行 |
2 |
d 删除该行 |
3 |
s/模式1/模式2/ 将第一次出现的模式 1 替换为模式 2 |
使用 sed 删除所有行
我们现在将了解如何使用 sed 删除所有行。再次调用 sed;但 sed 现在应该使用编辑命令删除行,用单个字母d表示-
$ cat /etc/passwd | sed 'd' $
可以指示 sed 从文件中读取数据,而不是通过管道向 sed 发送文件来调用 sed,如以下示例所示。
以下命令的作用与前面的示例完全相同,但没有使用 cat 命令 -
$ sed -e 'd' /etc/passwd $
sed 地址
sed 还支持地址。地址可以是文件中的特定位置,也可以是应应用特定编辑命令的范围。当 sed 没有遇到地址时,它会对文件中的每一行执行操作。
以下命令将基本地址添加到您一直使用的 sed 命令 -
$ cat /etc/passwd | sed '1d' |more daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh $
请注意,删除编辑命令之前添加了数字 1 。这指示 sed 在文件的第一行执行编辑命令。在此示例中,sed 将删除/etc/password的第一行并打印文件的其余部分。
sed 地址范围
我们现在将了解如何使用sed 地址范围。那么如果您想从文件中删除多行怎么办?您可以使用 sed 指定地址范围,如下所示 -
$ cat /etc/passwd | sed '1, 5d' |more games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh $
上述命令将应用于从 1 到 5 开始的所有行。这将删除前 5 行。
尝试以下地址范围 -
先生。 | 范围和描述 |
---|---|
1 |
'4,10d' 从第 4行到第 10行被删除 |
2 |
'10,4d' 仅删除第 10行,因为 sed 不能反向工作 |
3 |
'4,+5d' 这会匹配文件中的第 4 行,删除该行,继续删除接下来的五行,然后停止删除并打印其余内容 |
4 |
'2,5!d' 这将删除除第 2 行到第 5行之外的所有内容 |
5 |
‘1~3d’ 这将删除第一行,跳过接下来的三行,然后删除第四行。Sed 继续应用此模式直到文件末尾。 |
6 |
‘2~2d’ 这告诉 sed 删除第二行,跳过下一行,删除下一行,然后重复直到到达文件末尾 |
7 |
'4,10p' 打印从第 4行到第 10行 |
8 |
'4,d' 这会产生语法错误 |
9 |
',10d' 这也会产生语法错误 |
注意- 使用p操作时,应使用-n选项以避免重复行打印。检查以下两个命令之间的差异 -
$ cat /etc/passwd | sed -n '1,3p' Check the above command without -n as follows − $ cat /etc/passwd | sed '1,3p'
替换命令
替换命令(用s表示)将用您指定的任何其他字符串替换您指定的任何字符串。
要将一个字符串替换为另一个字符串,sed 需要了解第一个字符串结束位置和替换字符串开始位置的信息。为此,我们继续使用正斜杠 ( / ) 字符对两个字符串进行书尾处理。
以下命令将字符串root的行中第一次出现的字符串替换为字符串amrood。
$ cat /etc/passwd | sed 's/root/amrood/' amrood:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh ..........................
需要注意的是,sed 仅替换行中的第一个匹配项。如果字符串根在一行中出现多次,则仅替换第一个匹配项。
为了让 sed 执行全局替换,请将字母g添加到命令末尾,如下所示 -
$ cat /etc/passwd | sed 's/root/amrood/g' amrood:x:0:0:amrood user:/amrood:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh ...........................
替换标志
除了g标志之外,还可以传递许多其他有用的标志,并且您一次可以指定多个。
先生。 | 标志和描述 |
---|---|
1 |
G 替换所有匹配项,而不仅仅是第一个匹配项 |
2 |
数字 仅替换第 NUMBER个匹配项 |
3 |
p 如果进行了替换,则打印模式空间 |
4 |
w 文件名 如果进行了替换,则将结果写入 FILENAME |
5 |
我还是我 以不区分大小写的方式进行匹配 |
6 |
米或米 除了特殊正则表达式字符 ^ 和 $ 的正常Behave之外,此标志还导致 ^ 匹配换行符之后的空字符串,并且 $ 匹配换行符之前的空字符串 |
使用替代字符串分隔符
假设您必须对包含正斜杠字符的字符串进行替换。在这种情况下,您可以通过在s之后提供指定字符来指定不同的分隔符。
$ cat /etc/passwd | sed 's:/root:/amrood:g' amrood:x:0:0:amrood user:/amrood:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh
在上面的示例中,我们使用:作为分隔符而不是斜杠 /,因为我们尝试搜索/root而不是简单的根。
替换为空白
使用空替换字符串从/etc/passwd文件中完全删除根字符串-
$ cat /etc/passwd | sed 's/root//g' :x:0:0::/:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh
地址替换
如果您只想在第 10 行将字符串sh替换为字符串Quiet ,则可以按如下方式指定:
$ cat /etc/passwd | sed '10s/sh/quiet/g' root:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/quiet
同样,要进行地址范围替换,您可以执行如下操作 -
$ cat /etc/passwd | sed '1,5s/sh/quiet/g' root:x:0:0:root user:/root:/bin/quiet daemon:x:1:1:daemon:/usr/sbin:/bin/quiet bin:x:2:2:bin:/bin:/bin/quiet sys:x:3:3:sys:/dev:/bin/quiet sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh
从输出中可以看到,前五行将字符串sh更改为Quiet,但其余行保持不变。
匹配命令
您可以使用p选项和-n选项来打印所有匹配的行,如下所示 -
$ cat testing | sed -n '/root/p' root:x:0:0:root user:/root:/bin/sh [root@ip-72-167-112-17 amrood]# vi testing root:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh
使用正则表达式
在匹配模式时,您可以使用正则表达式,这提供了更大的灵活性。
检查以下示例,该示例匹配所有以daemon开头的行,然后删除它们 -
$ cat testing | sed '/^daemon/d' root:x:0:0:root user:/root:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh
以下是删除所有以sh结尾的行的示例-
$ cat testing | sed '/sh$/d' sync:x:4:65534:sync:/bin:/bin/sync
下表列出了正则表达式中非常有用的四个特殊字符。
先生。 | 特征及描述 |
---|---|
1 |
^ 匹配行的开头 |
2 |
$ 匹配行尾 |
3 |
。 匹配任意单个字符 |
4 |
* 匹配前一个字符零次或多次出现 |
5 |
[字符] 匹配 chars 中给定的任何一个字符,其中 chars 是字符序列。您可以使用 - 字符来指示字符范围。 |
匹配字符
再看几个表达式来演示元字符的用法。例如,以下模式 -
先生。 | 表达与描述 |
---|---|
1 |
/交流/ 匹配包含a+c、ac、abc、match和a3c等字符串的行 |
2 |
/a*c/ 匹配相同的字符串以及ace、yacc和arctic等字符串 |
3 |
/[tT]他/ 匹配字符串The和the |
4 |
/^$/ 匹配空行 |
5 |
/^.*$/ 匹配整行,无论它是什么 |
6 |
/ */ 匹配一个或多个空格 |
7 |
/^$/ 匹配空行 |
下表显示了一些常用的字符集 -
先生。 | 设定及说明 |
---|---|
1 |
[阿兹] 匹配单个小写字母 |
2 |
[AZ] 匹配单个大写字母 |
3 |
[a-zA-Z] 匹配单个字母 |
4 |
[0-9] 匹配单个数字 |
5 |
[a-zA-Z0-9] 匹配单个字母或数字 |
字符类关键字
一些特殊关键字通常可用于正则表达式,尤其是使用正则表达式的GNU 实用程序。这些对于 sed 正则表达式非常有用,因为它们简化了事情并增强了可读性。
例如,字符a 到 z和字符A 到 Z构成具有关键字[[:alpha:]]的此类字符
使用字母字符类关键字,此命令仅打印/etc/syslog.conf文件中以字母开头的那些行 -
$ cat /etc/syslog.conf | sed -n '/^[[:alpha:]]/p' authpriv.* /var/log/secure mail.* -/var/log/maillog cron.* /var/log/cron uucp,news.crit /var/log/spooler local7.* /var/log/boot.log
下表是 GNU sed 中可用字符类关键字的完整列表。
先生。 | 字符类别和描述 |
---|---|
1 |
[[:alnum:]] 字母数字 [az AZ 0-9] |
2 |
[[:α:]] 按字母顺序 [az AZ] |
3 |
[[:空白的:]] 空白字符(空格或制表符) |
4 |
[[:控制:]] 控制字符 |
5 |
[[:数字:]] 数字 [0-9] |
6 |
[[:图形:]] 任何可见字符(不包括空格) |
7 |
[[:降低:]] 小写字母 [az] |
8 |
[[:打印:]] 可打印字符(非控制字符) |
9 |
[[:标点符号:]] 标点符号 |
10 |
[[:空间:]] 空白 |
11 |
[[:上:]] 大写字母 [AZ] |
12 |
[[:x数字:]] 十六进制数字 [0-9 af AF] |
A& 符号引用
sed 元字符&表示匹配的模式的内容。例如,假设您有一个名为Phone.txt的文件,其中充满了电话号码,如下所示 -
5555551212 5555551213 5555551214 6665551215 6665551216 7775551217
您希望将区号(前三位数字)用括号括起来,以便于阅读。为此,您可以使用 & 替换字符 -
$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(&)/g' phone.txt (555)5551212 (555)5551213 (555)5551214 (666)5551215 (666)5551216 (777)5551217
在模式部分中,您将匹配前 3 位数字,然后使用&将这 3 位数字替换为周围的括号。
使用多个 sed 命令
您可以在单个 sed 命令中使用多个 sed 命令,如下所示 -
$ sed -e 'command1' -e 'command2' ... -e 'commandN' files
这里的command1到commandN是前面讨论的类型的 sed 命令。这些命令应用于 files 给出的文件列表中的每一行。
使用相同的机制,我们可以将上面的电话号码示例编写如下 -
$ sed -e 's/^[[:digit:]]\{3\}/(&)/g' \ -e 's/)[[:digit:]]\{3\}/&-/g' phone.txt (555)555-1212 (555)555-1213 (555)555-1214 (666)555-1215 (666)555-1216 (777)555-1217
注意- 在上面的示例中,我们没有将字符类关键字[[:digit:]]重复三次,而是将其替换为\{3\},这意味着前面的正则表达式匹配了三次。我们还使用\来给出换行符,并且必须在命令运行之前将其删除。
向后参考
& 元字符很有用,但更有用的是能够在正则表达式中定义特定区域。这些特殊区域可以用作替换字符串中的参考。通过定义正则表达式的特定部分,您可以使用特殊的引用字符引用这些部分。
要进行向后引用,您必须首先定义一个区域,然后向后引用该区域。要定义区域,请在每个感兴趣区域周围插入反斜杠括号。用反斜杠包围的第一个区域由\1引用,第二个区域由\2引用,依此类推。
假设phone.txt有以下文本 -
(555)555-1212 (555)555-1213 (555)555-1214 (666)555-1215 (666)555-1216 (777)555-1217
尝试以下命令 -
$ cat phone.txt | sed 's/\(.*)\)\(.*-\)\(.*$\)/Area \ code: \1 Second: \2 Third: \3/' Area code: (555) Second: 555- Third: 1212 Area code: (555) Second: 555- Third: 1213 Area code: (555) Second: 555- Third: 1214 Area code: (666) Second: 555- Third: 1215 Area code: (666) Second: 555- Third: 1216 Area code: (777) Second: 555- Third: 1217
注意- 在上面的示例中,括号内的每个正则表达式将由\1、\2等向后引用。我们在这里使用\来换行。在运行命令之前应将其删除。