Linux文本处理三剑客之一——sed详解——sed看这一篇就够啦~PS:文末有练习,来练练手吧

本文详细介绍了sed命令的原理、语法、常用选项和操作,包括p、a、i、c、r、s等,重点讲解了模式空间和暂存空间的使用,以及如何通过实例理解高级用法,适合学习和实践文本处理技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

sed --》 文本替换的命令,是支持正则表达式的非交互式流编辑器(stream editor)

sed大致原理图

sed语法命令格式

sed常用选项

sed的常用编辑命令

sed查找方式

sed的p命令示例

sed的a命令示例

sed的i命令示例

sed的c命令示例

sed的r命令示例

sed的s命令示例

sed的命令中&的用法

sed命令中标签的用法

sed里单引号和双引号的区别

sed高级用法:模式空间(pattern space)和暂存空间(hold space)相关的命令:

练习


sed --》 文本替换的命令,是支持正则表达式的非交互式流编辑器(stream editor)

sed - stream editor for filtering and transforming text  可以用来过滤和转换文本

sed大致原理图

模式空间:可以想成加工车间,根据某种模式将数据进行处理。

保持空间:可以想成仓库,我们在进行数据处理的时候,临时存放数据的地方

PS:正常情况下,如果不显示使用某些高级命令,保持空间不会使用到!

模式空间处理完一行数据,马上就是清空里面的内容,接着,再重复执行刚才的动作,文件中的新的一行被读入,直到文件处理完毕。

sed语法命令格式

  • sed  [选项]   sed编辑命令   输入文件
  • shell 命令  |  sed  [选项]   sed编辑命令
  • sed  [选项]   -f  sed脚本文件   输入文件

sed常用选项

  • -n:只显示匹配处理的行(否则会输出所有)
  • -e:执行多个编辑命令时(一般用;代替)
  • -i:直接在文件中进行修改,而不是输出到屏幕
  • -r:支持扩展正则表达式
  • -f:从脚本文件中读取内容并执行(文件中的编辑命令每行一个,不用;隔开)

sed的常用编辑命令

  • p:打印匹配行 print
  • d:删除指定行 delete
  • a:在匹配行后面追加 append
  • i:在匹配行前面插入 insert
  • c:整行替换
  • r:将文件的内容读入  read
  • w:将文本写入文件  write
  • s:字符串替换(匹配正则表达式)substitution
  • =:输出行号

sed查找方式

  • 根据行号
  • 根据模式 (正则表达式=字符+特殊符号)
  • 根据字符串

sed的p命令示例

根据行号:sed -n '行号1,行号2p' 输入文件

# 输出第1行
sed -n '1p' /etc/passwd

# 输出一到五行
sed -n '1,5p' /etc/passwd

# 输出最后一行
sed -n '$p' /etc/passwd

# 输出第四行及其后面五行
sed -n '4,+5p' /etc/passwd

# 只显示1~3行,4到最后一行都不显示
sed -n '4,$!p' /etc/passwd

# 不连续输出,只输出1,3,5行
sed -n '1p;3p;5p' /etc/passwd

# 可以设置步长值,输出单数行,步长为2
cat -n /etc/passwd|sed -n '1~2p'

根据模式:sed -n  '/模式/p'  输入文件

# 输出有root的行
sed -n '/root/p' /etc/passwd

# 以#或者$开头的行不显示
cat /etc/ssh/sshd_config |sed -rn '/^#|^$/!p'

# 显示以/结尾的行,需要转义
df -Th| sed -n '/\/$/p'

d命令和p命令一样,只需要将p改为d

sed的a命令示例

追加操作可以根据行号和模式匹配进行操作

[root@kafka01 1-8]# cat ip.txt
sanchuang
feng 123

# 在第一行后添加
sed -i '1a xie123' ip.txt  

[root@kafka01 1-8]# cat ip.txt
sanchuang
xie123
feng 123
sed -i '/xie/a xiexie' ip.txt

[root@kafka01 1-8]# cat ip.txt
sanchuang
xie123
xiexie
feng 123

sed的i命令示例

插入操作可以根据行号和模式匹配进行操作

[root@kafka01 1-8]# cat ip.txt
sanchuang
xie123
xiexie
feng 123

# 在有xie的前面一行都添加haha
sed -i '/xie/i haha' ip.txt

[root@kafka01 1-8]# cat ip.txt
sanchuang
haha
xie123
haha
xiexie
feng 123

sed的c命令示例

更改整行操作可以根据行号和模式匹配进行操作

# 将ha所在的行整行替换成后面的字符串
sed '/ha/c initdefault' ip.txt
sanchuang
xie123
initdefault
feng 123

# 将第三行改成后面的字符串
sed '3c ONBOOT=no' ifcfg-ens33

sed的r命令示例

读入操作可以根据行号和模式匹配进行操作

# 在fstab文件的末尾后面读入hosts文件的内容
sed '$r /etc/hosts' /etc/fstab

# 在/dev/sda1后面读入mtab文件的内容
df -h | sed '/dev\/sda1/r /etc/mtab'

以上的命令都是整行整行操作的,接下来的s替换操作的命令不是这样

sed的s命令示例

替换操作可以根据行号和模式匹配进行操作  s-->substitute

sed -n [行号或模式]s/查找内容/替换内容/[替换标记] 文件

替换标记有四种

  • 数字:替换每行的第几个
  • g:全局替换,否则只替换第一个字符串。例如ng从第n个开始替换
  • p:显示被执行替换操作的行,和-n合用
  • w:将执行替换操作的行输出到指定文件
sed -i '5  s/500/700/' ip.txt  --> 行号替换
sed -i '/^lxf/ s/500/200/' ip.txt  --> 模式替换

# 将文件中每行的第2个root替换为ROOT
sed -n 's/root/ROOT/2p' /etc/passwd

# 在2到10行开头(结尾)加上注释(问号)
sed -n '2,10 s/^/#/p' /etc/passwd
sed -n '2,10 s/$/?/p' /etc/passwd

# 将文件中的:号替换为换行符
sed 's/:/\n/g' /etc/passwd

# 将文件中bash替换成nologin,同时将sbin替换成bin
sed 's/bash/nologin/ ; s/sbin/bin/' /etc/passwd

# 永久关闭selinux
sed -i '/^SELINUX/ s/enforcing/disabled/' /etc/selinux/config

sed的s命令可以使用任意分隔符作为定界符(即转义字符\)

sed  -n '/^hello/s/\/bin\/bash/\/sbin\/nologin/p' /etc/passwd

sed  -n '/^hello/s|/bin/bash|/sbin/nologin|p' /etc/passwd

sed  -n '/^hello/s:/bin/bash:/sbin/nologin:p' /etc/passwd

sed的s命令支持\t \n

sed -n 's/^xie/\n111/p' /etc/passwd
# 把匹配到以xie开头后面加上tab
sed -n 's/^xie/&\t/p' /etc/passwd

sed的命令中有多次操作 -->用-e选项 或者 用分号;分开

sed -e 's/feng/fdy/' -e '/lxf/ s/500/200/' ip.txt

sed 's/feng/fdy/; /lxf/ s/500/200/' ip.txt

sed '{s/feng/fdy/; /lxf/ s/500/200/}' ip.txt

sed的命令中&的用法

  • & 用于表示替换命令中的匹配模式 --> 即 & 代表着我前面匹配到的全部字符

[root@kafka01 1-8sed]# echo "I have a fat cat"|sed 's/.at/".at"/g'

I have a ".at" ".at"

 

# 本意是想把匹配到的fat和cat加上引号,但这样的话却把匹配到的字符串替换成了".at"

# 所以我们使用&来代替前面匹配到的字符

[root@kafka01 1-8sed]# echo "I have a fat cat"|sed 's/.at/"&"/g'

I have a "fat" "cat"

 

# 将所有三位数字后面加个0 

# :900: 这里的900也算一个单词,空格等标点符号都是算单词的分割

[root@kafka01 1-8sed]# sed -rn 's/\<[0-9]{3}\>/&0/gp' /etc/passwd

sed命令中标签的用法

  • 标签:sed使用圆括号定义替换模式的部分字符
  • 标签可以方便在后面引用,每行指令最多使用9个标签
  •  \1 代表第一个圆括号定义的内容,\2 代表第二个,以此类推
# 把后面 .* 部分删除
sed -r 's/(^[0-z]+)(.*)/\1/' /etc/passwd

# 把前面 ^[0-z]+ 部分删除
sed -r 's/(^[0-z]+)(.*)/\2/' /etc/passwd

# 倒序输出
echo aaa bbb ccc | sed -r 's/([a-z]+) ([a-z]+) ([a-z]+)/\3 \2 \1/'
ccc bbb aaa

# 其实有些操作awk更方便
echo aaa bbb ccc| awk '{print $3,$2,$1}'
ccc bbb aaa

sed里单引号和双引号的区别

  • 双引号里可以引用shell的变量

sed高级用法:模式空间(pattern space)和暂存空间(hold space)相关的命令:

前面讲原理时也有提到模式空间,即处理文件内容的一个临时加工区。按行处理,处理完一行之后就会把模式空间中的内容打印到标准输出,然后自动清空里面的内容。

而这里说的暂存空间是sed中的另外一个区,此缓冲区中的内容不会自动清空,但也不会主动把此缓冲区中的内容打印到标准输出中。而是需要以下相关sed命令进行处理(可以man sed得到它们的英文解释)

d

删除 pattern space 的内容,开始下一个循环

n

输出模式空间行,读取下一行替换当前模式空间的行,执行下一条处理命令而非第一条命令。

N

 读入下一行,追加到模式空间行后面,此时模式空间有两行。

h

把模式空间里的行拷贝到暂存空间。

H

把模式空间里的行追加到暂存空间。

g

用暂存空间的内容替换模式空间的行。

G

把暂存空间的内容追加到模式空间的行后。

x

将暂存空间的内容于模式空间里的当前行互换。

对所选行以外的所有行应用命令。

以一个例子来说明上面命令的用法,例如有一个文件,我们需要用sed反序打印出文件的内容

sed '1!G;h;$!d' a.txt

接下来来解释一下这个命令的执行过程

首先第一行 first 进入 模式空间  处理时,不需要进行 G 即不把缓存空间的内容追加到模式空间(如果第一行进行了此操作,会有一个空内容在输出中),然后直接执行h,即把模式空间的行拷贝到暂存空间,最后把模式空间里的first删除,所以不会标准输出任何东西,此时暂存空间有first。

然后处理第二行,second进入模式空间接受处理,执行G,即将暂存空间的内容加入到模式空间,此时暂存空间有second、first,然后执行h,将模式空间的行拷贝到暂存空间,这个时候两个空间都有second、first,最后执行d把模式空间的内容删除,此时模式空间的内容为空,所以不会标准输出任何东西,此时暂存空间有second、first,简单画图描述一下

处理第三行时,third 进入模式空间接受处理,执行G,即将暂存空间的内容加入到模式空间,此时暂存空间有third、second、first,然后执行h,将模式空间的行拷贝到暂存空间,这个时候两个空间都有third、second、first,最后一行不需要执行d,就不用删除模式空间的内容,即直接输出模式空间的内容third、second、first.

模式空间和缓存空间的具体处理过程大概是这样,其实这两个空间类似于数据结构里的队列和栈,但不是完全一致,这两个知识点笔者也曾写过一篇文章,欢迎观看呀!

Python数据结构与算法—栈—队列—双向队列—栈与队列的应用—括号匹配问题—迷宫问题_m0_57053326的博客-CSDN博客

练习

1.截取nginx的access.log文件里3月18号18:20:38—18:25:56时间段内的所有访问日志(看你自己Linux中有哪些时间段的自己选择一些练习一下)

  • sed -n '1,9p' 
    • 截取1~9行
  • sed -n '/string1/,'/string2/p'
    • 同理,其实就是截取string1~string2之间的字符串
30/Oct/2021:18:20:38 --> string1
30/Oct/2021:18:25:56 --> string2

sed -n '/30\/Oct\/2021:18:20:38/,/30\/Oct\/2021:18:25:56/p' access.log

# 或者用正则,输出18:20~18:30分钟内的日志
sed -rn '/30\/Oct\/2021:18:(2[0-9]|30):(0[0-9]|[1-5][0-9])/p' access.log

2.自己编辑一个文件test.txt,内容如下:
0.0.0.0
1.1.1.1
2.2.2.2
输出以下形式:
0.0.0.0:80,1.1.1.1:80,2.2.2.2:80

cat num.txt |sed '1,2 s/$/:80,/' |sed  '3 s/$/:80/'|tr -s "\n" " "|tr -d " "

cat num.txt |sed -n 's/$/:80/;H;${x;s/\n/,/2g;p}' 

cat num.txt |tr '\n' ','|sed -n 's/,/:80&/g;p'|awk -F, 'OFS="," {print $1,$2,$3}'

cat num.txt |sed -n 's/$/:80,/p'|tr -s "\n" " "|awk -F, 'OFS="," {print $1,$2,$3}'|tr -d " "

3.给下列含有大写字母的行,在大写字母后追加数字2020 
   abcdSdddde
   islHishbxld
   goBkefji
   daanshXxge

sed -i  's/[A-Z]/&2020/g' c.txt 

sed -r 's/([a-z]+)([A-Z]+)(.*)/\1\22020\3/' sed_test.txt 

4.请将所有的非root用户的uid后面加一个0,gid前面加一个1

        提示:用标签或者&符号,并且不要直接对/etc/passwd操作喔!

sed -n -r '/^root/! s/([0-Z]+):([0-9]+):([0-9]+)/\20:1\3/p' passwd 

sed -r '/^root/! {s/\<[0-9]+\>/&0/1;s/\<[0-9]+\>/1&/2}' passwd

5.再给一些小练习,这些就不给出答案了,自己练练手就好啦(欢迎评论区交流呀!)

  • sed取出/etc/passwd文件的第一列
  • sed将PATH环境变量中的冒号换成换行
  • sed将PATH环境变量斜杠/换成斜杠\
  • 去掉/etc/passwd文件中第二个字段的x
  • 将/etc/sysconfig/network-scripts/ifcfg-ens33里的ONBOOT=no修改为yes或者修改下IPADDR后面的ip地址
  • 只显示ip add的ip地址
  • 将sshd_config里的端口号修改为8899

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值