zl程序教程

您现在的位置是:首页 >  系统

当前栏目

Linux命令之sed(流编辑器)

2023-09-11 14:17:21 时间

  sed流编辑器是一行一行的处理文件内容的,正在处理的内容存放在模式空间(缓冲区)内,处理完成后按照选项的规定进行输出或文件的修改。除非使用重定向存储输出,否则文件内容不会发生改变。

  sed主要用于自动编辑一个或多个文件,简化对文件的反复操作。并且sed也支持正则表达式,如果想使用扩展正则需要添加参数-r。

sed [选项] [附加命令] [输入文件]

(1).选项

-n,--quiet,--silent 取消自动打印模式空间内容
-e [附加命令],--expression=[附加命令或脚本] 添加附加命令到程序的运行列表,允许多个-e选项
-f [附加命令文件],--file=[附加命令文件] 读取文件的附加命令添加到程序的运行列表
-i[后缀],--in-place[=后缀] 根据附加命令编辑文件并保存,如果存在后缀则以文件名加后缀的形式生成一个备份文件,即有后缀的为原文件,无后缀的为修改后的文件
-c,--copy 当在-i模式下整理文件时,使用复制代替重命名(这里涉及到了文件的inode号)
-b,--binary 以二进制模式打开文件,对CR和LFS(变更请求和日志结果文件系统)不进行特殊对待,为兼容WIN32/CYGWIN/MSDOS/EMX
-l N,--line-length=N 为附加命令“l”指定所需的换行长度,显示形式为n-1个字符串+\,最后一行没有\。
--posix 禁用所有GNU扩展
-r,--regexp-extended 在附加命令中使用正则表达式
-s,--separate 将文件视为独立文件,而不是单个连续的长文件流
-u,--unbuffered 从输入文件加载最小数量的数据并更频繁地刷新输出缓冲区
-z,--null-data 用NUL字符分隔行

(2).附加命令

: [标签] 为附加命令b和t设置标签
b [标签] 跳转到设置好的标签;如果没有跟随标签则跳到附加命令末尾,结束该行的命令执行
t [标签] 如果s///(替换命令)执行成功,则跳转到设置好的标签;如果没有跟随标签则跳到附加命令末尾,结束该行的命令执行
T [标签] 与t相反,s///没成功时跳转到设置好的标签;如果没有跟随标签则跳到附加命令末尾,结束该行的命令执行
  示例:"s/root/xxx/;t a;s/0/1/g;:a"表示如果替换命令执行成功则不执行第二个替换命令;
     "/^root/b a;s/0/1/g;:a;s/root/xxx/g"表示如果当前行以root开头则不进行第一个替换命令,直接进行第二个替换命令
# [附加命令] 注释,如果存在于附加命令文件则持续到当前行,如果存在于附加命令则持续到该命令结束
{命令块} 将多条附加命令作为一个整体看待
[附加命令1];[附加命令2];... 分号将附加命令进行分隔,允许一次编辑多条附加命令
= 打印行号
a \[文本] 在当前行的下一行添加一行或多行文本,多行时可以使用\n转义字符进行换行
i \[文本] 在当前行的上一行添加一行或多行文本,多行时可以使用\n转义字符进行换行
c \[文本] 将当前行替换为一行或多行文本,多行时可以使用\n转义字符进行换行
  示例:"1i \[文本]"表示在第一行的上一行添加文本;"i \[文本]"表示在每行的上一行添加文本
q [退出代码] 立即退出sed命令,$?获取值为设置好的退出代码
Q [退出代码] 立即退出sed命令,$?获取值为设置好的退出代码
  注意:q和Q的区别在于,当没有取消自动打印模式空间时,q在退出前会打印当前模式空间,而Q则不会打印当前模式空间
r [文件名] 将文件内容添加到当前行的下一行
R [文件名] 文件内的每一行都作为一个单独的内容,从指定行开始,每读取一行输入文件的内容,在该行下一行添加内容
  示例:"1r [文件名]"表示在输入文件的第一行的下一行添加文件所有内容;"r [文件名]"表示在输入文件的每一行的下一行添加文件所有内容;
     "1R [文件名]"表示在输入文件的第一行的下一行添加文件的第一行内容,即使文件内存在多行也只运行一次;
     "R [文件名]"表示从输入文件的第一行开始,每行追加文件的对应的一行内容,直到输入文件或文件内容中的一个结束;
     "2,4R [文件名]"表示从输入文件的第二行到第四行,每行追加文件的第一行到第三行内容的一行内容。
d 删除模式空间
D 与d类似(有差异,但暂时不知道怎么触发)
h|H 拷贝或追加模式空间的内容到内存中的缓冲区
g|G 拷贝或追加内存中的缓冲区到模式空间
l 以视觉清晰的效果显示当前行,不会取消默认打印模块,转换符会以$的形式展现
l [长度] 以视觉清晰的效果显示当前行,指定了每次打印的长度,并且转行以\作为连接符(计算在长度内)
n|N 将下一行读或追加到模式空间,区别在于读取会覆盖原有内容,追加则不会
p 打印模式空间所有内容
P 打印模式空间内的第一行
s/[查找内容(正则表达式)]/[替换内容]/ 尝试将查找内容与模式空间内的内容匹配,如果成功则替换成功匹配的部分。替换内容可以使用特殊字符&来指代模式空间内的匹配内容,
  特殊转义字符\1到\9表示正则表达式中的相应匹配的子表达式。(s/[查找内容]/[替换内容]/g可以替换所有匹配到的内容)
w [文件名] 将当前模式空间内容写入到指定文件中,即另存为
W [文件名] 将当前模式空间内的第一行写入指定文件中
x 交换内存中的缓冲区和模式空间的内容

(3).实例

  说明:模式空间可以认为是sed命令每次读取文件内容的缓存区,默认一次读取文件一行。

  准备两个测试文件

[root@youxi1 ~]# vim readFile
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# vim a.txt
12345
67890

1)查看readFile文件的2到4行

[root@youxi1 ~]# sed -e "2,4p" readFile -n  //-e选项是默认选项,可以不写
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# sed "2,4p" readFile  //如果没有-n选项,sed会默认打印模式空间的内容
root:0:0:root:123456:password
abc:1:1:abc:password1
abc:1:1:abc:password1
xyz:2:2:abc:password2
xyz:2:2:abc:password2
root:3:4:abc:pass
root:3:4:abc:pass

2)-i选项与-c选项,重命名与复制

#没有-c选项时,-i选项是将原文件重命名成备份文件
[root@youxi1 ~]# ls -i readFile  //查看readFile的inode号
33575417 readFile
[root@youxi1 ~]# sed -i.bak "1,2p" readFile -n  //使用-i选项编辑并保存文件
[root@youxi1 ~]# ls -i readFile  //可以看到inode号与原文件的inode不同
33574999 readFile
[root@youxi1 ~]# cat readFile  //内容和原文件也不一样
root:0:0:root:123456:password
abc:1:1:abc:password1
[root@youxi1 ~]# ls -i readFile.bak  //备份文件的inode号与原文件的inode号相同
33575417 readFile.bak
[root@youxi1 ~]# cat readFile.bak  //内容和原文件也一样
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
#当-i选项与-c选项联合使用时
[root@youxi1 ~]# sed -i.cp "1,2p" readFile.bak -n -c
[root@youxi1 ~]# ls -i readFile.bak  //可以看到inode号和原文件相同
33575417 readFile.bak
[root@youxi1 ~]# cat readFile.bak  //内容与原文件不一样
root:0:0:root:123456:password
abc:1:1:abc:password1
[root@youxi1 ~]# ls -i readFile.bak.cp  //备份文件的inode号与原文件的inode号不同
34037099 readFile.bak.cp
[root@youxi1 ~]# cat readFile.bak.cp  //内容与原文件一样
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass

3)附加命令a \[文本],i \[文本],c \[文本]

[root@youxi1 ~]# rm -rf readFile readFile.bak
[root@youxi1 ~]# mv readFile.bak.cp readFile
[root@youxi1 ~]# cat readFile
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# sed "1a \add" readFile  //在第一行下方添加
root:0:0:root:123456:password
add
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# sed "1i \add" readFile  //在第一行上一行添加
add
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# sed "1c \add" readFile  //替换第一行
add
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# sed "1c \add\nabc\t123 456" readFile  //换行的转义字符\n,Tab的转义字符\t
add
abc 123 456
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass

4)附加命令=,打印行号

[root@youxi1 ~]# sed "=" readFile
1
root:0:0:root:123456:password
2
abc:1:1:abc:password1
3
xyz:2:2:abc:password2
4
root:3:4:abc:pass

5)附加命令d

[root@youxi1 ~]# sed "1,2d" readFile
xyz:2:2:abc:password2
root:3:4:abc:pass

6)附加命令s/[查找内容]/[替换内容]/(g)

[root@youxi1 ~]# sed "s/root/xxx/" readFile  //替换匹配到的第一个
xxx:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
xxx:3:4:abc:pass
[root@youxi1 ~]# sed "s/root/xxx/g" readFile  //替换匹配到的所有
xxx:0:0:xxx:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
xxx:3:4:abc:pass
[root@youxi1 ~]# sed "s/a.*p/1234/" readFile  //正则匹配内容并进行替换
root:0:0:root:123456:password
1234assword1
xyz:2:2:1234assword2
root:3:4:1234ass
[root@youxi1 ~]# sed "s/a.*p/&1234/" readFile  //正则匹配内容,保留原有的基础上进行替换
root:0:0:root:123456:password
abc:1:1:abc:p1234assword1
xyz:2:2:abc:p1234assword2
root:3:4:abc:p1234ass

  一样可以在s前加数字表示从第几行开始查找。

7)-r选项,使用正则表达式匹配指定行

[root@youxi1 ~]# sed -r "/^root/i \1234" readFile  //找到指定的行,在它的上一行添加内容
1234
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
1234
root:3:4:abc:pass
[root@youxi1 ~]# sed "/^.*abc/{s/^.*$/&\tName/}" readFile  //可以省略-r选项
root:0:0:root:123456:password
abc:1:1:abc:password1   Name
xyz:2:2:abc:password2   Name
root:3:4:abc:pass       Name
[root@youxi1 ~]# sed "/^.*abc/s/^.*$/&\tName/" readFile  //就连{}也可以省略,但不建议这样写,因为不方便理解
root:0:0:root:123456:password
abc:1:1:abc:password1   Name
xyz:2:2:abc:password2   Name
root:3:4:abc:pass       Name

8)附加命令q、Q

[root@youxi1 ~]# sed "/^.*abc/q" readFile  
root:0:0:root:123456:password
abc:1:1:abc:password1
[root@youxi1 ~]# sed "/^.*abc/Q" readFile 
root:0:0:root:123456:password

9)附加命令r [文件名]、R [文件名]

[root@youxi1 ~]# sed "/^root/r a.txt" readFile 
root:0:0:root:123456:password
12345
67890
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
12345
67890
[root@youxi1 ~]# sed "/^root/R a.txt" readFile  
root:0:0:root:123456:password
12345
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
67890

10)附加命令n、N、p、P、w、W

  首先一定要了解n(读取下一行到模式空间)、N(追加下一行到模式空间),以及默认打印模式空间的触发动作(预备读取下一行,结束sed命令)。注意:读取和追加到模式空间的行,sed命令就不再读取了。

[root@youxi1 ~]# sed "n;p" readFile 
root:0:0:root:123456:password  //预备执行附加命令n,触发默认打印当前模式空间。n执行完成后,模式空间内容是第二行内容
abc:1:1:abc:password1  //执行附加命令p,打印当前模式空间,模式空间内容不变
abc:1:1:abc:password1  //sed命令预备读取下一行,触发默认打印当前模式空间。读取下一行完成后,模式空间内容是第三行
xyz:2:2:abc:password2  //预备执行附加命令n,触发默认打印当前模式空间。n执行完成后,模式空间内容是第四行
root:3:4:abc:pass  //执行附加命令p,打印当前模式空间,模式空间内容不变
root:3:4:abc:pass  //sed命令结束,打印当前模式空间(此举是清空模式空间?)
[root@youxi1 ~]# sed "N;p" readFile   
root:0:0:root:123456:password
abc:1:1:abc:password1  //执行附加命令N,模式空间内容为第一行和第二行;执行附加命令p,打印当前模式空间
root:0:0:root:123456:password
abc:1:1:abc:password1  //sed命令预备读取下一行,触发默认打印当前模式空间。读取下一行完成后,模式空间内容是第三行
xyz:2:2:abc:password2
root:3:4:abc:pass  //执行附加命令N,模式空间内容由第三行变为第三第四行;执行附加命令p,打印当前模式空间
xyz:2:2:abc:password2
root:3:4:abc:pass  //sed命令结束,打印当前模式空间(此举是清空模式空间?)

  接着了解p(打印当前模式空间)和P(打印模式空间内的第一行)。在了解n和N的情况下,还是很好理解的。

[root@youxi1 ~]# sed "N;p" readFile -n
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# sed "N;P" readFile -n 
root:0:0:root:123456:password
xyz:2:2:abc:password2

  最后是w(保存当前模式空间到指定文件)和W(保存当前模式空间内的第一行到指定文件),和p、P的区别就是不打印,直接保存到文件中。了解了p和P,那么这两个也是很简单的。

[root@youxi1 ~]# sed "N;w b.txt" readFile -n
[root@youxi1 ~]# sed "N;W c.txt" readFile -n
[root@youxi1 ~]# cat b.txt
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
root:3:4:abc:pass
[root@youxi1 ~]# cat c.txt
root:0:0:root:123456:password
xyz:2:2:abc:password2

(4).sed增删改查

  sed命令比较常用的就是增删改查四项,“增”可以使用附加命令a \[文本]、i \[文本]、r [文件名]和R [文件名],“删”可以使用附加命令d,“改”可以使用附加命令c \[文本]和s/[查找内容]/[替换内容]/,“查”可以使用-r选项以及附加命令p