前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【数据处理】sed原理及使用举例(快速理解核心)

【数据处理】sed原理及使用举例(快速理解核心)

原创
作者头像
onephone
修改2022-03-30 14:07:06
3.1K5
修改2022-03-30 14:07:06
举报
文章被收录于专栏:onephone

在做数据开发中,经常需要通过shell脚本/命令来针对文本进行预处理,sed是一个很强大的流式处理命令,笔者几乎每天都会用到,在这统一梳理总结了下! 其实 sed 很简单,比vim简单很多了!

1. 基础

核心概念

  • 两个空间: 模式空间(pattern space); 交换空间(hold space 保持空间)
    • 模式空间:容纳当前行的缓冲区,即通过模式匹配到的行被读入该空间中
    • 保持空间:一个辅助缓冲区,可以和模式空间进行交互(通过h,H,g,G),但命令不能直接作用于该空间,在进行数据处理时作为“暂存区域”
原理概念
原理概念
  • 执行步骤: 1)读入一行数据到模式空间 2)在模式空间执行sed命令 3)将更新/修改后的内容输出 4)清空模式空间,并重复第一步,直到文件结束
    执行流程
    执行流程

联想记忆: 模式对应G(在左边), 交换对应H(在右边)

  • 两种执行方式:
    • 一般常用:sed [options] 'command' file(s)
    • 脚本文件:sed [options] -f scriptfile file(s)
  • 查看帮助:man sed
  • 官方查询文档:TLDP--The Linux Document Project

参数

  • sed最后会输出模式空间的所有内容(除非指定了-n参数)
  • 变量传递通过-v参数(建议)
  • -e: 支持多个编辑命令
    • 命令的执行顺序对结果有影响
    • (-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除1至5行,第二条命令用check替换test。命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。
      • sed -e '1,5d' -e 's/test/check/' example
代码语言:txt
复制
- 一个比-e更好的命令是`--expression`。它能给sed表达式赋值。  
`sed --expression='s/test/check/' --expression='/love/d' example`

正则匹配(元字符集)

代码语言:shell
复制
^
#锚定行的开始 如:/^sed/匹配所有以sed开头的行。   
$  
#锚定行的结束 如:/sed$/匹配所有以sed结尾的行。   
.  
#匹配一个非换行符的字符 如:/s.d/匹配s后接一个任意字符,然后是d。   
*  
#匹配零或多个字符 如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。  
[] 
#匹配一个指定范围内的字符,如/[Ss]ed/匹配sed和Sed。  
[^] 
#匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。  
\(..\) 
#保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers。  
& 
#保存搜索字符用来替换其他字符,如s/love/**&**/,love这成**love**。   
\<  
#锚定单词的开始,如:/\<love/匹配包含以love开头的单词的行。   
\>  
#锚定单词的结束,如/love\>/匹配包含以love结尾的单词的行。   
x\{m\}  
#重复字符x,m次,如:/0\{5\}/匹配包含5个o的行。   
x\{m,\}  
#重复字符x,至少m次,如:/o\{5,\}/匹配至少有5个o的行。   
x\{m,n\}  
#重复字符x,至少m次,不多于n次,如:/o\{5,10\}/匹配5--10个o的行。  

2. 常用命令

s 替换文本(匹配)

代码语言:shell
复制
#在整行范围内把test替换为mytest。如果没有g标记,则只有每行第一个匹配的test被替换成mytest。
$ sed 's/test/mytest/g' example 

#s选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印它。 
$ sed -n 's/^test/mytest/p' example   

#&符号表示替换换字符串中被找到的部份。所有以192.168.0.1开头的行都会被替换成它自已加 localhost,变成192.168.0.1localhost。 
 $ sed 's/^192.168.0.1/&localhost/' example  

#love被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。  
 $ sed -n 's/\(love\)able/\1rs/p' example

#不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。
$ sed 's#10#100#g' examplex   

#选定行的范围:逗号  
#所有在模板test和check所确定的范围内的行都被打印。 
 $ sed -n '/test/,/check/p' example   

#打印从第五行开始到第一个包含以test开始的行之间的所有行。
 $ sed -n '5,/^test/p' example  

#对于模板test和west之间的行,每行的末尾用字符串sed test替换。   
 $ sed '/test/,/check/s/$/sed test/' example 


#如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。
$ sed '/test/{ n; s/aa/bb/; }' example 

# 替换匹配到的文本
sed -i "s|^\(.*\)#\(SSLCertificateChainFile\).*|\1\2 /etc/apache2/ssl/1_root_bundle.crt|g" default-ssl.conf

# 替换匹配到的文本
sed -i "s+download.docker.com+${DOCKER_RE_REPO}+" /etc/yum.repos.d/docker-ce.repo

# 匹配再替换
sed -i "/^baseurl=http:/ { s,http://.*/hdp,http://${YUM_SERVER_IP}/hdp, } " hdp-utils.repo

# 匹配
# 如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。           
sed '/test/{ n; s/aa/bb/; }' example

# \和;都得转义
# 匹配slash无法用其他字符替换
# a:在匹配行的下一行追加, \可以不加,但加上\表示后面为追加内容,且表示空格也能插入       
sed -i "/\sinclude \/etc\/nginx\/conf.d\/\*.conf\;/a\    include /deploy/nginx/*.conf;" /etc/nginx/nginx.conf.bak

a,c,i,q,r,=,#,y

a\: 在当前行后面加入一行文本 i\: 在当前行上面插入文本 c: 用新的文本改变本行的文本 q: 退出Sed r: 从file中读行 w: 表示把行写入一个文件 (W: 追加) =: 打印当前行号码 #: 把注释扩展到下一个换行符以前。 y: 一个字符翻译为另外的字符(但是不用于正则表达式)

  • 用法举例
代码语言:shell
复制
# 从文件读入:r命令  
# file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面。  sed '/test/r file' example  

# 写入文件:w命令  
#在example中所有包含test的行都被写入file里。   
sed -n '/test/w file' example 

# 追加命令:a命令
# this is a example'被追加到以test开头的行后面,sed要求命令a后面有一个反斜杠。  
sed '/^test/a\\--->this is a example' example 
 
# 插入:i命令
# 如果test被匹配,则把反斜杠后面的文本插入到匹配行的前面。  
sed '/test/i\\  
 new line  
 -------------------------' example  
  
#变形:y命令  
#把1--10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令。   
sed '1,10y/abcde/ABCDE/' example 

#退出:q命令
#打印完第10行后,退出sed
sed '10q' example 。 

n,N

模式空间 n: 下一行 ,模式空间内容被覆盖 N: 将当前行和下一行(中间\n保留),一起追加到模式空间

  • N: 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。
代码语言:shell
复制
[root@VM_0_6_centos ~]# seq 6 | sed -n '1{n;p}'
2
seq 6 | sed -n '1{N;p}'
1
2
[root@VM_0_6_centos ~]# seq 6 | sed -n '2{N;p}'
2
3
[root@VM_0_6_centos ~]# seq 6 | sed -n '2{n;p}'
3

h,H,p,P,x

交换空间 h: 用模式空间内容覆盖交换空间 H: 将模式空间内容追加到交换空间 p/P: 模式空间输出 x: 交换空间&模式空间内容交换 g: 将交换空间的内容,覆盖到模式空间 G: 将交换空间的内容,追加到模式空间

  • 互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换
  • sed -e '/test/h' -e '/check/x' example
  • 例子
代码语言:shell
复制
[root@VM_0_6_centos ~]# seq 6 | sed '1h;3g'
1
2
1
4
5
6
[root@VM_0_6_centos ~]# seq 6 | sed '1h;3G'
1
2
3
1
4
5
6
  • 复杂的例子:
    • sed -n '/CST/h;/syncing/{x;//!p;g;P}
      • //!:简写,拿到最近的匹配结果,!表示若匹配不到

D,d

模式空间,删除 模式空间没有回车符,D/d一样 D/d执行后,都会跳到下一行(不管模式空间是否有内容)

  • 简单用法
代码语言:shell
复制
#删除第N行
sed -i 'Nd' filename
#删除第N~M行
sed -i 'N,Md' filename # file的[N,M]行都被删除
#删除shell变量表示的行号(配合for等语句使用)
sed -i "${var1},${var2}d" filename # 这里引号必须为双引号
#删除最后一行
sed -i '$d' filename
  • 打印带有hello段落(段和段之间用空隔分开)
    • d后面的操作不执行(直接跳到下一行)
    • 比较复杂,直接忽略: sed '/./{H;d;x;/hello/!d
  • awk实现:打印带有hello的段落
    • awk -v RS=' ' "/hello/
代码语言:shell
复制
cat >test.txt <<EOF
1111
2222
  3333hello
4444
  5555
6666
EOF

awk -v RS=' ' "/hello/" test.txt
3333hello
4444
  • 删除文件最后五行内容
    • 维持一个队列: 2-5行循环执行a,即N操作
    • 第6行的时候,打印模式空间中的第1行(P),并删除第1行(D)
    • 最后一行的时候,把模式空间清空($d
    • seq 7 | sed ':a;$d;N;2,5ba;P;D'
  • 波浪线用法a~b:a起始点,b间隔
  • 每隔两行输出一行
    • seq 10 | sed -n '1~3p'
      • 1~3: 1-从什么时候开始 ,3表示间隔3行
    • seq 10 | sed -n '0~3p'
代码语言:shell
复制
seq 10 | awk 'NR%3==1'
1
4
7
10

addr1,addr2用法

依次匹配addr1, addr2,匹配到即进行操作 addr1:匹配到后执行(开关打开),如果当前行>addr1

addr2:匹配到后执行(开关关闭)

  • 准确的理解seq 5 | sed '1,2d;1,2d'
    • 输出的应该是第4和第5行,因为第二行删除后,第一个1,2d关闭
    • 再读入第3行时,匹配到第2个1,2d,因为3>1,所以匹配成功,执行d删除第3行
    • 继续读入第4行后,发现2<4,匹配不成功,关闭,所以第4行不做d操作
    • 接着第5行后所有内容因为命令全部关闭,直接输出
代码语言:shell
复制
cat >test.txt <<EOF
a1
a2
a3
EOF

# 输出1-3行
sed '1,3{s/a/ax/}' test.txt
ax1
ax2
ax3

# 第一行就匹配到了a
sed '0,/a/{s/a/ax/}' test.txt
ax1
a2
a3

# 第一行匹配到1, 第二行匹配到a
sed '1,/a/{s/a/ax/}' test.txt
ax1
ax2
a3

# 一直匹配不到x
sed '1,/x/{s/a/ax/}' test.txt
ax1
ax2
ax3

t,b标签:

多用于做循环 t: 没有匹配到时跳转到label,无label则跳转到结尾

b: 调准到特定的label

  • :a: 定义label a
  • 把第偶数出现的1,改为0
代码语言:shell
复制
cat >test.txt <<EOF
1
2
1
3
1
1
EOF

sed '/1/{:a;n;s/1/0/;tb;ba;:b}' test.txt
1
2
0
3
1
0

3. 简单自测

  • G,H作用,以及和g,h区别
    • G,H: 追加,G (交换空间->模式空间) H(模式空间->交换空间)
    • g,h: 覆盖
  • x作用
    • 模式空间和交换空间交换
  • echo abc | sed 's/.*/&\n&/'
    • &即引用前面匹配的结果
  • sed每隔10行输出一个
  • seq 5 | sed -n 'x;p'
  • seq 5 | sed -n 'x;p;x'
  • sed '$!N;$!D'sed 'N;D', sed '$!D;D'

4. 组合应用

  • find, sed:同时替换多个文件内的服务名
代码语言:shell
复制
find . -type f -print0 | xargs -0 sed -i "s/<SERVER_NAME>/${SVR_NAME}/g" 

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 基础
    • 核心概念
      • 参数
        • 正则匹配(元字符集)
        • 2. 常用命令
          • s 替换文本(匹配)
            • a,c,i,q,r,=,#,y
              • n,N
                • h,H,p,P,x
                  • D,d
                    • addr1,addr2用法
                      • t,b标签:
                      • 3. 简单自测
                      • 4. 组合应用
                      相关产品与服务
                      命令行工具
                      腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档