当前位置: 首页 > Linux

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

时间:2023-04-06 03:29:30 Linux

与vim不同,sed是一个非交互式的文本编辑器,它是面向字符流的,每一行数据都经过sed处理后输出。sed[OPTION]...[script][file]...sed的工作过程是这样的:首先,初始化两个databuffermodespace和holdspace;sed读取一行输入(从标准输入或文件),去掉尾随的换行符(\n)并将其放入模式空间,然后开始对模式空间中的字符串执行'sed命令',每个命令都可以有一个与之关联的地址,地址可以看作是一个条件,只有当条件为真时才执行相关命令;当所有的可执行命令都处理完后,还在模式空间中的字符串会被追加一个换行符,然后打印出来;读取下一行输入后,做同样的过程,直到自愿退??出(q)或输入结束。地址address可以是下面的形式1,number表示行号2,first~step表示从第一(number)行开始,每一步(number)行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影响的字符串才会被输出。-ffile表示从文件中读取sed命令-i表示就地修改。当应用该选项时,sed将创建一个临时文件并将处理结果输出到该文件中。处理后,临时文件将被覆盖为原始文件。-r表示使用扩展正则表达式命令p表示打印模式空间的内容,通常与选项-n一起使用[root@centos7~]#seq512345[root@centos7~]#只输出第二个到第四行[root@centos7~]#seq5|sed-n'2,4p'234[root@centos7~]#d删除模式空间的内容,立即处理下一行输入。#删除最后一行[root@centos7~]#seq5|sed'$d'1234[root@centos7~]#q立即退出,不再处理任何命令和输入(只接受单个地址)[root@centos7~]#seq5|sed'/3/q'123[root@centos7~]#n如果不使用option-n,输出patternspace内容后,读取下一行input,覆盖内容当前模式空间。如果没有更多的输入行,sed退出执行。[root@centos7~]#seq9|sed-n'n;p'2468[root@centos7~]#注意多条命令用分号隔开s/regexp/replacement/flag表示替换pattern中匹配的正则模式空格替换表达式正则表达式的一部分。这里的符号/可以替换为任何单个字符。[root@centos7~]#echo"hello123world"|sed's/[0-9]\+/,/'hello,world#注意这里的+需要转义,如果使用选项-r则不用需要在替换1中转义。\n(n是1-9的数字)表示对正则表达式中分组(...)的引用;[root@centos7~]#echo"hello123world"|sed-r's/[a-z]+([0-9]+)[a-z]+/\1/'123[root@centos7~]#echo"hello123world"|sed-r's/([a-z]+)[0-9]+([a-z]+)/\1,\2/'hello,world2,&表示模式空间中匹配正则表达式的所有部分;[root@centos7~]#echo"hello123world"|sed-r's/[0-9]+/:&:/'hello:123:world3,\L将后面的字符转为小写,直到\U或\E出现;4、\l将下一个字符转为小写;5、\U将后面的字符转换为大写,直到出现\L或\E;6.\u将下一个字符转为大写;7、\E停止从\L或\U开始的大小写转换;[root@centos7~]#echo"hello123world"|sed-r's/^([a-z]+)[0-9]+([a-z]+)$/\U\1\E,\u\2/'HELLO,World[root@centos7~]#flag1,nnumbern表示替换第n个匹配项[root@centos7~]#head-1/etc/passwdroot:x:0:0:root:/root:/bin/bash#替换冒号第五部分分隔为空[root@centos7~]#head-1/etc/passwd|sed's/[^:]\+://5'root:x:0:0:/root:/bin/bash2,g表示全局替换[root@centos7~]#echo"hello123world"|sed's/./\U&\E/'Hello123world[root@centos7~]#[root@centos7~]#echoo"hello123world"|sed's/./\U&\E/g'HELLO123WORLD[root@centos7~]##当数字n和g同时使用时,表示从第n个匹配项开始替换为最后一个匹配项[root@centos7~]#head-1/etc/passwd|sed's/[^:]\+://4g'root:x:0:/bin/bash/3,p表示if替换成功,则打印模式空间的内容4.wfile表示如果替换成功,则将模式空间的内容输出到文件file。5.I和i表示在匹配正则表达式时不区分大小写。[root@centos7~]#echo'HELLO123world'|sed-r's/[a-z]+//ig'123[root@centos7~]#6,M和m的意思是开启常规多行模式(如前所述前)。(例子当谈到commandN)y/source-chars/dest-chars/将source-chars中的字符替换为dest-chars中相应位置的字符,/可以替换为任何其他单个字符,source-chars与dest-chars中的字符数必须一致,不能使用正则表达式。[root@centos7~]#echohello|sed'y/el/LE/'hLEEo[root@centos7~]#atext表示输出模式空格的内容然后追加输出文本内容[root@centos7~]#seq3|sed'1,2ahello'1hello2hello3[root@centos7~]#itext表示在输出模式空间内容之前输出文本内容[root@centos7~]#seq3|sed'$ihello'12hello3[root@centos7~]#ctext表示删除匹配地址或地址范围的模式空间的内容,输出text的内容。如果是单个地址,则输出每一行匹配,如果是地址范围,则只输出一次。[root@centos7~]#seq5|sed'1,3chello'hello45[root@centos7~]#seq5|sed'/^[^3-4]/chello'hellohello34hello=表示打印当前输入行number[root@centos7~]#seq100|sed-n'$='100[root@centos7~]#seq100|sed-n'/^10\|^20/='1020100[root@centos7~]#越狱|表示logic或者rfile表示在当前模式空间内容输出后读取文件内容输出[root@centos7~]#catfilehelloworld[root@centos7~]#seq3|sed'1,2rfile'1helloworld2helloworld3[root@centos7~]#wfile表示将模式空间的内容输出到文件中。将一行内容读入模式空间后,将下一行内容添加到模式空间(此时模式空间的内容如下line1\nline2),如果没有下一行,sed会退出.[root@centos7~]#seq10|sed-n'N;s/\n//p'12345678910[root@centos7~]##s命令m标志示例[root@centos7~]#seq3|sed'N;s/^2/xxx/'123[root@centos7~]#seq3|sed'N;s/^2/xxx/m'1xxx3[root@centos7~]#seq3|sed'N;s/1$/xxx/'123[root@centos7~]#seq3|sed'N;s/1$/xxx/M'xxx23D如果模式空间没有换行(比如命令N产生换行符),它与命令d具有相同的效果;如果包含换行符,则删除第一行的内容,然后对模式空间中剩余的内容重新开始一轮处理。(注意:D后面的命令会被忽略)[root@centos7~]#seq5|sed'N;D'5[root@centos7~]#seq5|sed'N;N;D'345P打印模式第一行空格[root@centos7~]#seq10|sed-n'N;P'13579[root@centos7~]#seq10|sed-n'N;N;P'147#注意另一个区别在两种写法的输出中[root@centos7~]#seq10|sed-n'1~3P'14710g将patternspace中的内容替换为holdingspace中的内容[root@centos7~]#seq5|sed-n'g;N;s/\n/xx/p'xx2xx4[root@centos7~]#G在模式空间追加一个换行符,然后在换行符后面追加保持空间的内容。(此时patternspace中的内容如PATTERN\nHOLD)[root@centos7~]#seq5|sed'G;s/\n/xx/'1xx2xx3xx4xx5xxh将holdspace中的内容替换为内容在模式空间中(注意此时模式空间中的内容还没有被清除)[root@centos7~]#seq5|sed-n'h;G;s/\n/xx/p'1xx12xx23xx34xx45xx5[root@centos7~]#seq5|sed-n'h;G;G;s/\n/xx/gp'1xx1xx12xx2xx23xx3xx34xx4xx45xx5xx5H在保持空间追加一个换行符,然后在换行符后面追加模式空间的内容。(此时空间内容保持为HOLD\nPATTERN)[root@centos7~]#seq3|sed-n'H;G;s/\n/xx/gp'1xxxx12xxxx1xx23xxxx1xx2xx3[root@centos7~]#x交换模式空间和保持空间的内容[root@centos7~]#seq9|sed-n'1!{x;N};s/\n//p'3254769#Theonesin{...}arecommandsGroup:label指定分支命令的标签位置(不允许地址匹配)blabel无条件跳转到标签分支,如果省略标签,则跳转到整个命令的末尾(即开始nextread)#例如删除xml文件中间的注释部分(之间的部分是注释,可以是多行)sed'//!{N;ba};d}'server.xml#表示匹配,匹配后删除模式空间中的内容-->#比如nagios的配置文件中,有很多definehost{...}字段,如下图:definehost{usewindows-serverhost_nameserverAhostgroups060202alias060202contact_groupsyuaddress192.168.1.1}#现在需要删除ip地址为192.168.1.1的网段,可以这样做:sed-i'/definehost/{:a;N;/}/!ba;/192\.168\.1\.1/d}'file#注意和前面例子的区别。t标签有成功执行一次输入后的s替换命令只跳转到该标签,如果省略该标签,则跳转到整个命令的末尾(即开始下一次读取)#如行和列转换[root@centos7~]#seq10|sed':a;$!N;s/\n/,/;ta'1,2,3,4,5,6,7,8,9,10[root@centos7~]##例如将MAC地址78A35114F798改为78格式一个冒号:A3:51:14:F7:98[root@centos7temp]#echo'78A35114F798'|sed-r':a;s/\B\w{2}\b/:&/;ta'78:A3:51:14:F7:98[root@centos7temp]##这里的\b表示匹配词边界,\B表示匹配任何其他非词边界的字符#当然还有其他方法也可以使用实现:[root@centos7temp]#echo'78A35114F798'|sed-r's/..\B/&:/g'78:A3:51:14:F7:98[root@centos7temp]#Tlabel一次输入后,只要没有替换命令执行成功,就会跳转到该label。如果省略标签,则跳转到整个命令的末尾(即开始下一次读取)。z表示清除模式空间中的内容,s/.*//做同样的事情,但效率更高更多例子1.删除匹配行的上一行和下一行#例如输入数据是命令seq10的输出(当然也可以是其他任何文件内容)#删除上一行和下一行下一行匹配5[root@centos7temp]#seq10|sed-n'$!N;/\n5/{s/.*\n//p;N;d};P;D'1235789102,mergeoddandevenlines#Inputdataiscommand对于seq11的输出,要求奇数和偶数分别放在同一行#输出第一行`1357911`,第二行`246810`[root@centos7~]#seq11|sed-nr'$!N;2!G;s/([^\n]+)\n((.+)\n)?(.+)\n(.+)/\4\1\n\5\3/;h;$p'1357911246810[root@centos7~]#3.合并多个文件#a.txt的文本内容:01125101014001021231000140020312550101400304126100014004051281000140050612310001400607127100014007081231000140080912810101400910125101014010111231000140111212610001401213123100014013#文本b.txt的内容:A124101012006/02/152009/01/314002B123100012006/08/312008/08/294001C126100012008/05/232008/05/224002D128100011992/12/101993/06/304001E126600011992/05/111993/06/014005#要求输出a.txt的第二列和b的内容.txt中第二列相同的行,并追加b.txt中对应的两列日期。#如:021231000140022006/08/312008/08/29sed-rn'/^[01]/ba;H;:a;G;s/^((..)(.*)([^\n]+)).*\3(([^]*){2}).*/\1\5/p'b.txta.txt#当然如果用awk处理的话,解法比较简单懂一些:awk'NR==FNR{a[$2]=$3FS$4;next}{if($2ina)print$0,a[$2]}'b.txta.txt是加深sed的各种命令要了解其特点,请自行分析这三个例子。各种命令的组合使用,再加上正则表达式的强大能力,使得sed能够处理所有的计算问题。但由于代码可读性差,难以理解。通常,sed用作文本编辑器,对文本进行非交互式流式处理。理解以上命令的含义并熟练使用它们,你就会发现sed的强大之处。