Linux中的sed命令

sed 命令用于对文本进行过滤和变形处理,是一种流编辑器。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。

sed 命令主要用来自动编辑一个或多个文件,可以将数据行进行替换、删除、新增、选取等特定工作,简化对文件的反复操作,编写转换程序等。

命令格式

sed 命令格式如下:

1
2
3
4
5
sed [选项] '动作' file

或者将sed的command写在一个文件内

sed [选项] -f scriptfile file

选项

sed命令中的选项是可选的,包含以下选项:

  • -e:直接在命令行模式上进行sed动作编辑,这个选项为默认选项;
  • -f:将sed的动作写在一个文件内,用-f scriptfile 的方式来执行该文件内的动作;
  • -i:直接修改文件内容;
  • -n:只打印模式匹配的行,其他内容不打印;
  • -r:支持扩展表达式;
  • -h或--help:显示帮助信息;
  • -V或--version:显示版本信息。

动作

动作的语法分为查询和修改两个部分,两部分的语法都不一样。

修改

sed命令的关于修改的语法如下:

1
sed [匹配条件][基础动作]\[要添加或者取代的字符串]
  • 匹配条件:这里的匹配条件可以是指定行数,也可以像正则表达式一样去动态匹配,不过匹配规则是后面要提到的元字符集;
  • 基础动作:这里就对上一个步骤中匹配到的行进行的动作,包括新增行、删除行、替换行、替换指定字符、打印等等;
  • 要添加或者取代的字符串:当基础动作为新增、替换行、替换指定字符时,当字段就必须要填,否则可以不填。

说明
语法在一些特殊动作是会与上述语法有差别,比如当基础动作为s时,语法格式就会变为:

1
[匹配条件]s/[匹配的字符]/[新的字符]

还有一个选项就是全面替换g标记

1
[匹配条件]/s/[匹配的字符]/[新的字符]/g

代表会替换每一行中的所有匹配。

动作包含以下基础动作:

  • a:在当前行下面插入文本;
  • i:在当前行上面插入文本;
  • c:把选定的行替换为新的文本;
  • d:删除当前行;
  • p:打印当前行;
  • s:替换指定字符

查询

sed命令关于查询时语法如下:

1
sed /[查询条件]/[基础动作]

查询条件基本是一些字符串,而基础动作在查询是一般是p,也有可能是执行的一组命令;

如果是执行命令时,那使用花括号括起来,命令之间使用分号分割:

1
sed -n '/oo/{s/oo/kk/;p}' param.txt

以上命令则是找到 oo 对应的行,执行后面花括号中的一组命令,将oo 替换为kk,然后输出。

元字符集

该字符集是用于在sed中的匹配条件的编写,支持一些动态规则的匹配,语法如下:

  • ^:匹配行开始,/^sed/就匹配所有以sed开头的行;
  • $:匹配行结束,/sed$/就匹配所有以sed结尾的行;
  • .:匹配一个非换行符的任意字符,/s.d/匹配s后接一个任意字符结尾是d的字符串;
  • *:匹配0个活多个字符,/*sed/匹配所有是一个或多个空格后紧跟sed的行;
  • []:匹配一个指定范围内的字符,/[sS]/ed/匹配sed和Sed;
  • [^]:匹配一个不在指定范围内的字符,/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行;
  • x\{m\}:重复字符x,m次,/0\{5\}/就匹配包含5个0的行;
  • x\{m,\}:重复字符x,至少m次,/0\{5,\}就匹配至少有5个0的行;
  • x\{m,n\}:重复字符x,至少m次,不多于n次,/0\{5,9\}就匹配至少5个0,但不多于9个0的行。

示例

下面示例使用/etc/passwd文件作为输入,使用nl命令去将文件内的每一行添加行号,取前面10行保存成新文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nl /etc/passwd | head -n 10 >> param.txt

## 以下是文件内容
cat param.txt
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

在指定行添加字符串

添加行的话要确定是在指定行前面加还是后面加,确定这个之后就可以敲命令了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sed '4a\newLine' param.txt

## 输出
❯ sed '4a\newLine' param.txt
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
newLine
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

命令中的4就是匹配条件,a就是基础动作,\后面跟的就是要添加的newLine字符串。

上面例子就是使用a基础动作,在第4行后面添加newLine 字符串。如果想在第4行前面也就是第3行后面,上面的基础动作就从a替换到i。

那如何添加多行字符串呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sed '2a\oneLine\
> twoLine' param.txt
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
oneLine
twoLine
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

每一行之间都必须要以反斜杠 \ 来进行新行标记。

注意事项
注意,在 oneLine\ 后的下一行里,行首的> 不是我们敲的,是系统自动生成的。

以行为单位范围删除

将参数文件内的第2~5行删除

1
2
3
4
5
6
7
sed '2,5d' param.txt
1 root:x:0:0:root:/root:/bin/bash
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

上述命令的动作为2,5d,基础动作是d,将匹配条件2,5的行进行删除,在输出中也可以看出,2-5行已经被删除了。

除了删除指定范围行,也可以删除从指定行到最后一行,使用不知道最后一行的行数场景:

1
2
3
sed '3,$d' param.txt
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

上述命令就删除了从第三行开始,到最后一行的内容。

以行为单位的替换和显示

将第2-5行的内容取代成为 No 2-5 number

1
2
3
4
5
6
7
8
sed '2,5c\No 2-5 number' param.txt 
1 root:x:0:0:root:/root:/bin/bash
No 2-5 number
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

仅列出文件内的第5-7行

1
2
3
4
sed -n '5,7p' param.txt 
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin

使用-n选项,只打印那些匹配的行,使用5,7p动作,匹配条件是5,7,基础动作是p,意思是打印。

数据匹配

搜索param.txt文件中有root关键字的行

1
2
3
4
sed -n '/root/p' param.txt 
1 root:x:0:0:root:/root:/bin/bash
11 root:x:0:0:root:/root:/bin/bash
12 root:x:0:0:root:/root:/bin/bash

数据匹配并删除

删除所有包含oo的行,其他行输出

1
2
3
4
5
6
7
8
sed '/oo/d' param.txt 
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin

数据匹配并执行命令

执行root对应的行,将root替换为superadmin,再输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
sed  '/root/{s/root/superadmin/}' param.txt 
1 superadmin:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
11 superadmin:x:0:0:root:/root:/bin/bash
12 superadmin:x:0:0:root:/root:/bin/bash

从上面可以看出,所有行中的第一个root都被替换掉了,但如果我要每一行中的root都全部替换成superadmin,该如何做呢?

那就是在子命令中添加基础动作g,该动作是代表全局替换:

1
2
3
4
5
6
7
8
9
10
11
12
13
sed  '/root/{s/root/superadmin/g}' param.txt 
1 superadmin:x:0:0:superadmin:/superadmin:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
11 superadmin:x:0:0:superadmin:/superadmin:/bin/bash
12 superadmin:x:0:0:superadmin:/superadmin:/bin/bash

从结果可以看出,所有的root都已经被替换成superadmin了。

参考资料


Linux中的sed命令
https://sunshinechen.cn/2024/03/06/Linux中的sed命令/
作者
sunshine
发布于
2024年3月6日
许可协议