Linux基础命令介绍十:文本流编辑 sed

与vim不同,sed是一种非交互式的文本编辑器,同时它又是面向字符流的,每行数据经过sed处理后输出。


  1. sed [OPTION]... [script] [file]... 

sed的工作过程是这样的:首先,初始化两个数据缓冲区模式空间和保持空间;sed读取一行输入(来自标准输入或文件),去掉结尾的换行符(\n)后置于模式空间中,然后针对模式空间中的字符串开始执行‘sed命令’,每个命令都可以有地址与之相关联,地址可以看成是条件,只有在条件成立时,相关的命令才被执行;所有可执行命令都处理完毕后,仍处于模式空间中的字符串会被追加一个换行符后打印输出;之后读取下一行输入做同样的处理,直到主动退出(q)或输入结束。

地址

地址可以是如下的形式

1、number 表示行号

2、first~step 表示从first(数字)行开始,每隔step(数字)行

3、$ 表示最后一行(注意当出现在正则表达式中时表示行尾)

4、/regexp/ 表示匹配正则表达式regexp(关于正则表达式,请参见这一篇)

5、\%regexp% 表示匹配正则表达式regexp,%可以换成任意其他单个字符。(用于regexp包含斜线/的情况)

6、/regexp/I 匹配正则表达式regexp时不区分大小写

7、/regexp/M 启用正则多行模式,使$不止匹配行尾,还匹配n或r之前的位置;使^不止匹配行首,还匹配n或r之后的位置。此时可以用(\`)匹配模式空间的开头位置,用(\')匹配模式空间的结束位置。

还可以用逗号,分隔两个地址来表示一个范围

表示从匹配第一个地址开始,直到匹配第二个地址或文件结尾为止。如果第二个地址是个正则表达式,则不会对第一个地址匹配行进行第二个地址的匹配;如果第二个地址是行号,但小于或等于第一个地址匹配行行号,则只会匹配一行(第一个地址匹配行)。

8、0,/regexp/ 这种情况下,正则表达式regexp会在第一行就开始进行匹配。只有第二个地址是正则表达式时,第一个地址才能用0。

9、addr1,+n表示匹配地址addr1和其后的n行。

10、addr1,~n表示从匹配地址addr1开始,直到n的倍数行为止。

如果没有给出地址,所有的行都会匹配;在地址或地址范围后追加字符!表示对地址取反,所有不匹配的行才会被处理。

选项

-n 默认时每一行处理过的字符串都会被打印输出,此选项表示关闭此默认行为。只有被命令p作用的字符串才会被输出。

-f file表示从file中读取sed命令

-i 表示原地修改。应用此选项时,sed会创建一个临时文件,并将处理结果输出到此文件,处理完毕后,会将此临时文件覆盖至原文件。

-r 表示使用扩展的正则表达式

命令

p表示打印模式空间内容,通常配合选项-n一起使用


  1. [root@centos7 ~]# seq 5 
  2. [root@centos7 ~]# 只输出第二行到第四行 
  3. [root@centos7 ~]# seq 5|sed -n '2,4p' 
  4. [root@centos7 ~]#   

d 删除模式空间内容,立即处理下一行输入。


  1. #删除最后一行 
  2. [root@centos7 ~]# seq 5|sed '$d' 
  3. [root@centos7 ~]#  

q 立即退出,不再处理任何命令和输入(只接受单个地址)


  1. [root@centos7 ~]# seq 5|sed '/3/q' 
  2. [root@centos7 ~]#  

n 如果没有使用选项-n,输出模式空间中内容后,读取下一行输入并覆盖当前模式空间内容。如果没有更多的输入行,sed会退出执行。


  1. [root@centos7 ~]# seq 9|sed -n 'n;p' 
  2. [root@centos7 ~]# 注意多个命令用分号分隔  

s/regexp/replacement/flag 表示用replacement替换模式空间中匹配正则表达式regexp的部分。在这里符号/可以换成任意单个字符。


  1. [root@centos7 ~]# echo "hello123world"|sed 's/[0-9]\+/,/'   
  2. hello,world 
  3. #注意这里+需要转义,如果使用选项-r则无需转义  

在replacement中

1、\n (n为1-9中的一个数字)表示对正则表达式中分组(...)的引用;


  1. [root@centos7 ~]# echo "hello123world"|sed -r 's/[a-z]+([0-9]+)[a-z]+/\1/' 
  2. 123 
  3. [root@centos7 ~]# echo "hello123world"|sed -r 's/([a-z]+)[0-9]+([a-z]+)/\1,\2/' 
  4. hello,world  

2、&表示模式空间中所有匹配regexp的部分;


  1. [root@centos7 ~]# echo "hello123world"|sed -r 's/[0-9]+/:&:/' 
  2. hello:123:world  

3、\L 将后面的字符转化成小写直到 \U 或 \E 出现;

4、\l 将下一个字符转化为小写;

5、\U 将后面的字符转化成大写直到 \L 或 \E 出现;

6、\u 将下一个字符转化为大写;

7、\E 停止由 \L 或 \U 起始的大小写转化;


  1. [root@centos7 ~]# echo "hello123world"|sed -r 's/^([a-z]+)[0-9]+([a-z]+)$/\U\1\E,\u\2/' 
  2. HELLO,World 
  3. [root@centos7 ~]#   

flag

1、n数字n表示替换第n个匹配项


  1. [root@centos7 ~]# head -1 /etc/passwd 
  2. root:x:0:0:root:/root:/bin/bash 
  3. #替换冒号分隔的第五部分为空 
  4. [root@centos7 ~]# head -1 /etc/passwd|sed 's/[^:]\+://5' 
  5. root:x:0:0:/root:/bin/bash  

2、g表示全局替换


  1. [root@centos7 ~]# echo "hello123world"|sed 's/./\U&\E/' 
  2. Hello123world 
  3. [root@centos7 ~]#  
  4. [root@centos7 ~]# echo "hello123world"|sed 's/./\U&\E/g' 
  5. HELLO123WORLD 
  6. [root@centos7 ~]# 
  7. #当数字n和g同时使用时,表示从第n个匹配项开始替换一直到最后匹配项 
  8. [root@centos7 ~]# head -1 /etc/passwd|sed 's/[^:]\+://4g' 
  9. root:x:0:/bin/bash/  

3、p表示如果替换成功,则打印模式空间内容。

4、w file表示如果替换成功,则输出模式空间内容至文件file中。

5、I和i表示匹配regexp时不区分大小写。


  1. [root@centos7 ~]# echo 'HELLO123world'|sed -r 's/[a-z]+//Ig' 
  2. 123 
  3. [root@centos7 ~]#  

6、M和m表示启用正则多行模式(如前所述)。(讲命令N时再举例)


  1. [root@centos7 ~]# echo hello|sed 'y/el/LE/'       
  2. hLEEo 
  3. [root@centos7 ~]#  

a text表示输出模式空间内容后追加输出text内容


  1. [root@centos7 ~]# seq 3|sed '1,2a hello'  
  2. hello 
  3. hello 
  4. [root@centos7 ~]#  

i text表示输出模式空间内容之前,先输出text内容


  1. [root@centos7 ~]# seq 3|sed '$ihello' 
  2. hello 
  3. [root@centos7 ~]#   

c text表示删除匹配地址或地址范围的模式空间内容,输出text内容。如果是单地址,则每个匹配行都输出,如果是地址范围,则只输出一次。


  1. [root@centos7 ~]# seq 5|sed '1,3chello' 
  2. hello 
  3. [root@centos7 ~]# seq 5|sed '/^[^3-4]/c hello'  
  4. hello 
  5. hello 
  6. hello  

=表示打印当前输入行行号


  1. [root@centos7 ~]# seq 100|sed -n '$=' 
  2. 100 
  3. [root@centos7 ~]# seq 100|sed -n '/^10\|^20/=' 
  4. 10 
  5. 20 
  6. 100 
  7. [root@centos7 ~]# 转义的|表示逻辑或  

r file表示读取file的内容,并在当前模式空间内容输出之后输出


  1. [root@centos7 ~]# cat file  
  2. hello world 
  3. [root@centos7 ~]# seq 3|sed '1,2r file' 
  4. hello world 
  5. hello world 
  6. [root@centos7 ~]#   

w file表示输出模式空间内容至file中

N读入一行内容至模式空间后,再追加下一行内容至模式空间(此时模式空间中内容形如 line1\nline2 ),如果不存在下一行,sed会退出。


  1. [root@centos7 ~]# seq 10|sed -n 'N;s/\n/ /p' 
  2. 1 2 
  3. 3 4 
  4. 5 6 
  5. 7 8 
  6. 9 10 
  7. [root@centos7 ~]# 
  8. #s命令的m flag举例 
  9. [root@centos7 ~]# seq 3|sed 'N;s/^2/xxx/'  
  10. [root@centos7 ~]# seq 3|sed 'N;s/^2/xxx/m'     
  11. xxx 
  12. [root@centos7 ~]# seq 3|sed 'N;s/1$/xxx/'  
  13. [root@centos7 ~]# seq 3|sed 'N;s/1$/xxx/M' 
  14. xxx 
  15. 3  

D如果模式空间中没有新行(如命令N产生的新行),则和命令d起同样作用;如果包含新行,则会删除第一行内容,然后对模式空间中剩余内容重新开始一轮处理。(注意:D后面的命令将会被忽略)


  1. [root@centos7 ~]# seq 5|sed 'N;D'   
  2. [root@centos7 ~]# seq 5|sed 'N;N;D'    
  3. 5  

P打印模式空间中第一行内容


  1. [root@centos7 ~]# seq 10|sed -n 'N;P'  
  2. [root@centos7 ~]# seq 10|sed -n 'N;N;P' 
  3. #注意另一种写法输出中的不同 
  4. [root@centos7 ~]# seq 10|sed -n '1~3P'  
  5. 10  

g用保持空间中的内容替换模式空间中的内容


  1. [root@centos7 ~]# seq 5|sed -n 'g;N;s/\n/xx/p' 
  2. xx2 
  3. xx4 
  4. [root@centos7 ~]#   

G追加一个换行符到模式空间,然后再将保持空间中的内容追加至换行符之后。(此时模式空间中内容形如 PATTERN\nHOLD )


  1. [root@centos7 ~]# seq 5|sed 'G;s/\n/xx/'   
  2. 1xx 
  3. 2xx 
  4. 3xx 
  5. 4xx 
  6. 5xx  

h用模式空间中的内容替换保持空间中的内容(注意此时模式空间中的内容并没有被清除)


  1. [root@centos7 ~]# seq 5|sed -n 'h;G;s/\n/xx/p' 
  2. 1xx1 
  3. 2xx2 
  4. 3xx3 
  5. 4xx4 
  6. 5xx5 
  7. [root@centos7 ~]# seq 5|sed -n 'h;G;G;s/\n/xx/gp' 
  8. 1xx1xx1 
  9. 2xx2xx2 
  10. 3xx3xx3 
  11. 4xx4xx4 
  12. 5xx5xx5  

H追加一个换行符到保持空间,然后再将模式空间中的内容追加至换行符之后。(此时保持空间中内容形如 HOLD\nPATTERN )


  1. [root@centos7 ~]# seq 3|sed -n 'H;G;s/\n/xx/gp' 
  2. 1xxxx1 
  3. 2xxxx1xx2 
  4. 3xxxx1xx2xx3 
  5. [root@centos7 ~]#   

x交换模式空间和保持空间的内容


  1. [root@centos7 ~]# seq 9|sed -n '1!{x;N};s/\n//p' 
  2. 25 
  3. 47 
  4. 69 
  5. #处于{...}之中的是命令组  

: label为分支命令指定标签位置(不允许地址匹配)

b label无条件跳转到label分支,如果省略了label,则跳转到整条命令结尾(即开始下一次读入)


  1. #如删除xml文件中注释部分(<!--...-->之间的部分是注释,可以多行) 
  2. sed '/<!--/{:a;/-->/!{N;ba};d}' server.xml 
  3. #表示匹配<!--开始,在匹配到-->之前一直执行N,匹配到-->之后删除模式空间中内容 
  4. #如在nagios的配置文件中,有许多define host{...}的字段,如下所示: 
  5. define host{ 
  6. use windows-server 
  7. host_name serverA 
  8. hostgroups 060202 
  9. alias 060202 
  10. contact_groups yu 
  11. address 192.168.1.1 
  12. #现在需要删除ip地址是192.168.1.1的段,可以这样: 
  13. sed -i '/define host/{:a;N;/}/!ba;/192\.168\.1\.1/d}' file 
  14. #注意和前一个例子中的区别  

t label在一次输入后有成功执行的s替换命令才跳转到label,如果省略了label,则跳转到整条命令结尾(即开始下一次读入)


  1. #如行列转换 
  2. [root@centos7 ~]# seq 10|sed ':a;$!N;s/\n/,/;ta' 
  3. 1,2,3,4,5,6,7,8,9,10 
  4. [root@centos7 ~]# 
  5. #如将MAC地址78A35114F798改成带冒号的格式78:A3:51:14:F7:98 
  6. [root@centos7 temp]# echo '78A35114F798'|sed -r ':a;s/\B\w{2}\b/:&/;ta' 
  7. 78:A3:51:14:F7:98 
  8. [root@centos7 temp]# 
  9. #这里\b表示匹配单词边界,\B表示匹配非单词边界的其他任意字符 
  10. #当然也可以采用其他的方式实现: 
  11. [root@centos7 temp]# echo '78A35114F798'|sed -r 's/..\B/&:/g' 
  12. 78:A3:51:14:F7:98 
  13. [root@centos7 temp]#  

T label在一次输入后只要没有替换命令被成功执行就跳转到label,如果省略了label,则跳转到整条命令结尾(即开始下一次读入)

z表示清除模式空间中内容,和s/.*//起相同的作用,但更有效。

更多例子

1、删除匹配行的上一行和下一行


  1. #例如输入数据为命令seq 10的输出(当然也可以是任意其他文件内容) 
  2. #要求删除匹配5那一行的前一行和后一行 
  3. [root@centos7 temp]# seq 10|sed -n '$!N;/\n5/{s/.*\n//p;N;d};P;D' 
  4. 10  

2、合并奇偶数行


  1. #输入数据为命令seq 11的输出,要求分别将奇数和偶数分别放在同一行 
  2. #输出第一行`1 3 5 7 9 11`,第二行`2 4 6 8 10` 
  3. [root@centos7 ~]# seq 11|sed -nr '$!N;2!G;s/([^\n]+)\n((.+)\n)?(.+)\n(.+)/\4 \1\n\5 \3/;h;$p' 
  4. 1 3 5 7 9 11 
  5. 2 4 6 8 10  
  6. [root@centos7 ~]#   

3、合并多文件


  1. #文本a.txt的内容: 
  2. 01 12510101 4001 
  3. 02 12310001 4002 
  4. 03 12550101 4003 
  5. 04 12610001 4004 
  6. 05 12810001 4005 
  7. 06 12310001 4006 
  8. 07 12710001 4007 
  9. 08 12310001 4008 
  10. 09 12810101 4009 
  11. 10 12510101 4010 
  12. 11 12310001 4011 
  13. 12 12610001 4012 
  14. 13 12310001 4013 
  15. #文本b.txt的内容: 
  16. A 12410101 2006/02/15 2009/01/31 4002 
  17. B 12310001 2006/08/31 2008/08/29 4001 
  18. C 12610001 2008/05/23 2008/05/22 4002 
  19. D 12810001 1992/12/10 1993/06/30 4001 
  20. E 12660001 1992/05/11 1993/06/01 4005 
  21. #要求输出a.txt内容中第二列和b.txt中第二列相同的行,并追加b.txt中对应的两个日期列。 
  22. #形如:02 12310001 4002 2006/08/31 2008/08/29 
  23. sed -rn '/^[01]/ba;H;:a;G;s/^((..)( .*)( [^\n]+)).*\3(( [^ ]*){2}).*/\1\5/p' b.txt a.txt 
  24. #当然如果使用awk来处理的话,解决思路更容易理解一些: 
  25. awk 'NR==FNR{a[$2]=$3FS$4;next}{if($2 in a)print $0,a[$2]}' b.txt a.txt  

为加深对sed各种命令特性的理解,请自行分析这三个例子。

各种命令的组合使用,再加上正则表达式的强大能力,使得sed可以处理所有能够计算的问题。但由于代码可读性不强,理解起来比较困难,通常使用sed作为一个文本编辑器,对文本做非交互的流式处理。理解上述各个命令的含义,熟练使用它们,就会发现sed的强大之处。

作者:vvpale

来源:51CTO

时间: 2024-08-03 15:35:36

Linux基础命令介绍十:文本流编辑 sed的相关文章

Linux基础命令介绍十五:推陈出新

本文介绍ip.ss.journalctl和firewall-cmd,它们旨在代替linux中原有的一些命令或服务. 1.ip ip [OPTIONS] OBJECT COMMAND  ip是iproute2软件包里面的一个强大的网络配置工具,它能够替代一些传统的网络管理工具,例如ifconfig.route等,使用权限为超级用户. OPTIONS是修改ip行为或改变其输出的选项. OBJECT是要获取信息的对象.包括: address   表示设备的协议(IPv4或IPv6)地址  link  

Linux基础命令介绍十二:磁盘与文件系统

本篇讲述磁盘管理相关的命令.计算机中需要持久化存储的数据一般是保存在硬盘等辅助存储器中.硬盘一般容量较大,为了便于管理和使用,可以将硬盘分成一到多个逻辑磁盘,称为分区;为使分区中的文件组织成操作系统能够处理的形式,需要对分区进行格式化(创建文件系统);在linux中,对于格式化后的分区,还必须经过挂载(可简单理解为将分区关联至linux目录树中某个已知目录)之后才能使用. 1.df 显示文件系统磁盘空间使用量 [root@centos7 temp]# df -h  文件系统           

Linux基础命令介绍四:文本编辑vim

本文介绍vim(版本7.4)的一般用法. vim是功能强大的文本编辑器,是vi的增强版. vim [options] [file ..]  使用vim编辑一个文件的最常用命令就是: vim file  其中file可以是一个新文件,也可以是原有文件.这样的命令执行后将打开编辑器,显示文件file的内容.如图所示: 如果是一个新文件,底部左边会显示"file" [新文件]的字样,右边显示0,0-1表示当前光标所在行数和字符数.如果打开的是一个老文件,底部左边显示"file&qu

linux基础命令介绍五:文本过滤 grep

在linux中经常需要对文本或输出内容进行过滤,最常用的过滤命令是grep grep [OPTIONS] PATTERN [FILE...]  grep按行检索输入的每一行,如果输入行包含模式PATTERN,则输出这一行.这里的PATTERN是正则表达式(参考前一篇,本文将结合grep一同举例). 输出文件/etc/passwd中包含root的行: [root@centos7 temp]# grep root /etc/passwd  root:x:0:0:root:/root:/bin/bas

Linux基础命令介绍八:文本分析awk

awk是一种模式扫描和处理语言,在对数据进行分析处理时,是十分强大的工具. awk [options] 'pattern {action}' file...  awk的工作过程是这样的:按行读取输入(标准输入或文件),对于符合模式pattern的行,执行action.当pattern省略时表示匹配任何字符串;当action省略时表示执行'{print}';它们不可以同时省略. 每一行输入,对awk来说都是一条记录(record),awk使用$0来引用当前记录: [root@centos7 ~]#

Linux基础命令介绍六:网络

本文将讲述网络相关命令,作者假定读者具备TCP/IP协议栈的基础知识.对于相关命令及其输出只介绍它的基本的使用方法和大概的描述,具体协议将不作详细解释. 如今网络无疑是很重要的,linux系统中提供了丰富的网络测试与管理命令.我们来一起看看它们. 1.ping 发送TCMP回显请求报文,并等待返回TCMP回显应答. ping [OPTIONS]... destination  这里的目标destination可以是目的IP地址或者域名/主机名 选项-c指定发送请求报文的次数,当ping没有任何选

Linux基础命令介绍七:网络传输与安全

本篇接着介绍网络相关命令 1.wget 文件下载工具 wget [option]... [URL]...  wget是一个非交互的下载器,支持HTTP, HTTPS和FTP协议,也可以使用代理.所谓'非交互'意思是说,可以在一个系统中启动一个wget下载任务,然后退出系统,wget会在完成下载(或出现异常)之后才退出,不需要用户参与. [root@centos7 temp]# wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomca

Linux基础命令介绍十一:软件包管理

linux中软件包的管理随着系统发行版本的不同而不同,RPM和DPKG为最常见的两类软件包管理工具,分别应用于基于rpm软件包的linux发行版和基于deb软件包的linux发行版.本文只描述RPM的使用方法,另一种命令不同,但用法类似,就不做介绍了. 1.rpm RPM包管理器 选项-q表示查询系统安装的软件包 [root@centos7 ~]# rpm -q sudo  sudo-1.8.6p7-16.el7.x86_64  [root@centos7 ~]# rpm -q nginx  未

Linux基础命令介绍九:进程与内存

计算机存在的目的就是为了运行各种各样的程序,迄今我们介绍的绝大多数命令,都是为了完成某种计算而用编程语言编写的程序,它们以文件的形式保存在操作系统之中(比如/bin下的各种命令);但静态的程序并不能"自发的"产生结果,只有在操作系统中为其指定输入数据并运行起来,才能得到输出结果.而操作系统中程序运行的最主要表现形式便是进程. 静态程序可以长久的存在,动态的进程具有有限的生命周期.每次程序运行的开始(如键入一条命令后按下回车键),操作系统都要为程序的运行准备各种资源,这些资源绝大多数都处