sed的命令格式:的工作原理是怎样的?
sed是streameditor的简写,英文称之为“流编辑器”。
sed命令是一个面向行处理的工具,它以“行”为处理单位,针对每一行进行处理,处理后的结果会输出到标准输出(STDOUT)。你会发觉sed命令是很懂礼貌的一个命令,它不会对读取的文件做任何轻率的更改,而是将内容都输出到标准输出中。
我们来瞧瞧sed的命令格式:
sed command file
sed的工作原理是哪些昨晚我们说了,sed命令是面向“行”进行处理的,每一次处理一行内容。处理时,sed会把要处理的行存贮在缓冲区中,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直至文件末尾。这个缓冲区被称为“模式空间”(patternspace)。
如上面所说linux命令passwd,在这个处理过程中,sed命令并不会对文件本身进行任何修改。
我们来一起看一个最最简单的sed命令的事例,让你们对它有个感性的认识。
#我们先来看看原文件的内容 [roc@roclinux ~]$ cat roc.txt test 1 test2 testtest XtestX BBtest #我们想用sed命令来删除文件中带字符“2”的行 [roc@roclinux ~]$ sed '/2/d' roc.txt test 1 testtest XtestX BBtest
此反例是借助sed来删掉roc.txt文件中富含字符“2”的行。见到了吧,事例很简单,这个命令的command部份是/2/d,并且它是用单冒号括上去的。你也一定要学着这样做,用到sed,别忘了用单冒号将command部份括上去。
/2/d中的d表示删掉,意思是说,只要某行内容中富含字符2,就删除这一行。(sed所谓的删掉都是在模式空间中执行的,不会真正改动roc.txt原文件。)想用sed命令实现cut命令的疗效如果我们想实现类似于cut-d:-f1/etc/passwd的疗效,也就是以逗号为间隔符提取第1个域,用sed命令应当如何操作呢?
#先来一起看看/etc/passwd文件的内容 [roc@roclinux ~]$ head -n 5 /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin #我们这回用sed命令来提取文件中每行的第一个域, 间隔符是冒号 [roc@roclinux ~]$ head -n 5 /etc/passwd|sed 's/:.*$//' root bin daemon adm lp
见到了吧,我们将command部份指定成了's/:.*$//',表示我们要把每一行的第一个逗号到结尾的部份都清空,这样留下的便是第一个逗号前的内容啦。sed都有什么好用的选项说到sed命令的选项,就不得不提-n选项,想把这个选项介绍清楚,还是要费一些头脑和笔端的。
后面提及,sed会将模式空间里的行经过处理后输出到标准输出,这是默认的处理方法。也就是说,除非你使用“d”来删掉此行,否则经过“模式空间”处理的行都是会被输出到标准输出(屏幕)上的。我们一上去看下边的事例:
#还是先来看看原文件的内容 [roc@roclinux ~]$ cat roc.txt 1 2 3 4 5 #仔细看, 输出中出现了两个“4” [roc@roclinux ~]$ sed ‘/4/p’ roc.txt 1 2 3 4 4 5
看,所有的原始文件内容都被输出来了,但是富含字符4的行被输出了两遍。
但这就是sed命令的工作原理,它会不问青红皂白地把经过处理的行先输出下来,之后再执行前面的动作。(在这儿我们设定了p,表示复印此行。)这显著不符合我们的本意,我们只是想让sed命令找到富含4的行再输出。
这时侯,不妨加上-n选项试一试,你会发觉,结果显得如你所愿了。
[roc@roclinux ~]$ sed -n '/4/p' roc.txt 4
-n选项会很严肃地警告sed命令:除非是明晰表明要输出的行,否则不要给我胡乱输出。-n选项时常和p配合使用,其涵义就是,输出这些匹配的行。command部份花样好多还记得我们在后面介绍过的,sed命令的命令格式是这样的:
$ sed command file
其中,command部份是sed命令的真谛,对command部份的把握程度决定了你是不是sed大神。
command部份可以分为两块知识:一块是范围设定,一块是动作处理。
范围设定,可以采用两种不同的形式来抒发:指定行数:例如‘3,5’表示第3、第4和第5行;而‘5,$’表示第5行至文件最后一行。模式匹配:例如/^[^dD]/表示匹配行首不是以d或D开头的行。
而动作处理部份,会提供很丰富的动作供你选择,下边就来介绍几个最常用的动作吧:展示sed实力的时侯到了事实胜过诡辩,我们准备通过四个反例,让你们感遭到sed命令真的是一位“实力派”选手。
第一个反例,我们来显示test文件的第10行到第20行的内容:
#我们采用了刚才提到的指定行区间的方法 [roc@roclinux ~]$ sed -n '10,20p' test
第二个反例,我们尝试将所有以d或D开头的行里的所有大写x字符变为小写X字符:
[roc@roclinux ~]$ sed '/^[dD]/s/x/X/g' test
这个用法值得一讲,我们在command部份采用了/AA/s/BB/CC/g的句型格式,这表示我们要匹配到文件中带有AA的行,但是将这种行中所有的BB替换成CC。
第三个事例,我们要删掉每行最后的两个字符:
#点号表示一个单个字符, 两个点号就表示两个单个字符 [roc@roclinux ~]$ sed 's/..$//' test
有人可能会问,用sed‘/..$/d’test为何不行呢,d不是表示删掉么?用d是不行的,这是由于d表示删掉整行内容,而非字符。'/..$/d'表示的是匹配所有末尾富含两个字符的行,之后删掉这一整行内容,似乎这和我们的本意是偏颇的。
第四个反例,我们希望删掉每一行的前两个字符:
[roc@roclinux ~]$ sed 's/..//' test
通过这四个反例,相信你们对sed命令的最常见用法早已有了很直观的认识了,不妨在自己的实际工作中把这种知识用上去吧。&符号的妙用我们依然通过一个场景来讲解这个知识点。
#按照惯例, 先展示文件的内容 [roc@roclinux ~]$ cat mysed.txt Beijing London #我们使用到了&符号, 大家试着猜一猜它的作用 [roc@roclinux ~]$ sed 's/B.*/&2008/' mysed.txt Beijing2008 London
不卖关子linux版qq,答案出炉啦,这个命令的作用是将包含‘B.*’的字符串前面加上2008四个字符。这个命令中我们用到了&字符,在sed命令中,它表示的是“之前被匹配的部份”,在我们的事例中其实就是Beijing啦!
我们再通过一个反例加强一下你们对&符号的理解:
#这个例子或许更易理解 [roc@roclinux 20160229]$ sed 's/Bei/&2008/' mysed.txt Bei2008jing London
sed中的括弧有深意在sed命令中,虽然小括弧‘()’也是有深意的。我们开门见山,通过一个反例,让你们见识一下小括弧的威力:
[roc@roclinux ~]$ echo "hello world" | sed 's/(hello).*/world 1/' world hello
我们看见,原先是“helloworld”,经过sed的处理,输出弄成了“worldhello”。
这个反例中就用到了小括弧的知识,我们称之为“sed的预储存技术”,也就是命令中被“(”和“)”括上去的内容会被依次暂存上去,储存到1、2…里面。这样你就可以使用‘N’形式来调用那些预储存的内容了。
来继续看一个反例,我们希望只在每行的第一个和最后一个Beijing前面加上2008字符串,言下之意就是,不仅每行的第一个和最后一个2008之外,这一行中间出现的Beijing旁边就不要加2008啦。这个需求,真的是很复杂很个性化,但sed命令始终可以挺好地满足:
#先看下文件内容, 第一行中出现了4个Beijing [roc@roclinux ~]$ cat mysed.txt Beijing Beijing Beijing Beijing London London London London #效果实现啦, 可是, 命令真的好复杂 [roc@roclinux ~]$ sed 's/(Beijing)(.*)(Beijing)/12008232008/' mysed.txt Beijing2008 Beijing Beijing Beijing2008 London London London London
这个命令确实足够复杂,用流行的语言说就是“足够催泪”。这个反例中我们再度使用了预储存技术,储存了三项内容,分别代表第一个Beijing、中间的内容、最后的Beijing。而针对1和3,我们在其前面追加了2008这个字符串。更聪明的定位行范围实践是学习知识最好的方式,相信你们看了这个反例后,就明白怎么更好地定位行范围了:
#文件内容展示一下 [roc@roclinux ~]$ cat mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 Beijing 2007 #我们想展示匹配了2005的行和2007的行之间的内容 [roc@roclinux ~]$ sed -n ‘/2005/,/2007/p’ mysed.txt Beijing 2005 Beijing 2006 Beijing 2007
我们使用/2005/来匹配行范围的首行,用/2008/来匹配行范围的尾行。可以见到,在匹配尾行时,只要碰到第一个符合要求的行,才会停止,而不会再继续向后匹配了。所以,sed命令只是匹配到了第一个2007,并没有匹配到第二个2007。用-e选项来设置多个command还记得command部份吧,现今有一个好消息要告诉你,那就是sed命令可以包含不只一个command。假如要包含多个command,只需在每位command上面分别加上一个-e选项即可。
#我们通过2个-e选项设置了两个command [roc@roclinux ~]$ sed -n -e ‘1,2p’ -e ‘4p’ mysed.txt Beijing 2003 Beijing 2004 Beijing 2006
有一个地方值得你们注意,那就是-e选项的前面要立刻接command内容,不容许再参杂其他选项。
-e选项支持设置多个command,这本来是一件好事情,让我们可以更便捷地实现一些替换疗效。并且,这也给我们带来了幸福的苦恼,如果我们设定了好多个command,那它们的执行次序是如何的呢?
倘若这一点不搞明白,-e选项带来的其实只有混乱而非方便。我们来一起瞧瞧下边的事例:
#先看看文件的内容 [roc@roclinux ~]$ cat mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 #我们设置了两个command [roc@roclinux ~]$ sed -e ‘s/Beijing/London/g’ -e ‘/Beijing/d’ mysed.txt London 2003 London 2004 London 2005 London 2006 London 2007 London 2008
前一个command表示将Beijing替换为London,而后一个command表示要删掉包含了Beijing字符串的行,然而最后的结果却是输出了所有行,并没有发觉被删掉的行。这是由于第一个command早已将Beijing都替换成了London,所以怪第二个command找不到Beijing了。
我们再来把里面事例中的command颠倒一下位置,瞧瞧疗效怎么:
#我们先指定删除动作, 再指定替换动作 [roc@roclinux 20160229]$ sed -e '/Beijing/d' -e 's/Beijing/London/g' mysed.txt [roc@roclinux 20160229]$
通过这两个小反例雨林木风linux,我们可以很清晰地看见,多个command之间,是根据在命令中的先后次序来执行的。用-f选项设定command文件假如你的sed命令的command部份很长,这么可以将内容讲到一个单独的文件中,之后使用-f选项来指定这个文件作为我们sed命令的command部份:
#这是我们事先写好的文件 [roc@roclinux ~]$ cat callsed /2004/,/2006/p #我们用-f选项来指定command文件 [roc@roclinux ~]$ sed -n -f callsed mysed.txt Beijing 2004 Beijing 2005 Beijing 2006
挺好理解吧,-f选项并不难,但是我会常常使用,由于一些比较常用的匹配规则,我就会存到单独的文件中,不用再费头脑记忆啦。内容插入sed命令远比你想像的要强悍,它除了可以处理本行内容,还可以在这一行的前面插入内容:
#我们将要插入的内容保存到一个单独的文件中 [roc@roclinux ~]$ cat ins.txt ====China==== #展示一下我们要处理的文件 [roc@roclinux ~]$ cat mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 #看, 我们使用r来实现插入 [roc@roclinux ~]$ sed ‘/2005/r ins.txt’ mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 ====China==== Beijing 2006 Beijing 2007 Beijing 2008
通过疗效可以看下来,我们在文件中的富含2005字符串的行的下边一行插入了ins.txt文件的内容。
不仅可以通过指定文件来插入外,似乎还可以使用a在特定行的“下面”插入特定内容:
#文件内容 [roc@roclinux ~]$ cat new.txt Beijing 2004 Beijing 2005 Beijing 2006 #我们希望在2004的下一行插入China [roc@roclinux ~]$ sed ‘/2004/aChina’ mysed.txt Beijing 2003 Beijing 2004 China Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008
可以看见,我们只要使用a之后加上要插入的内容就可以轻松实现啦。
有些同学会问,既然可以在一行的下边插入内容,那是否可以在一行的前面插入内容呢?答案是其实可以,那就是使用i动作:
[roc@roclinux ~]$ sed ‘/2004/iChina’ mysed.txt Beijing 2003 China Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008
说一说y动作在介绍y动作之前,我们先来瞧瞧它可以实现哪些疗效:
#原文件内容 [roc@roclinux ~]$ cat mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 #y就是按照字符顺序, 实现前后的替换 [roc@roclinux 20160229]$ sed 'y/ei/ie/' mysed.txt Biejeng 2003 Biejeng 2004 Biejeng 2005 Biejeng 2006 Biejeng 2007 Biejeng 2008
这个反例似乎早已很清楚了,我们希望将所有的e和i互换。
有些同学会问,y///和s///有哪些区别呢?主要有以下两点:
这时,一些GEEK似乎会想到一种情况,那就是y/ee/ei/会形成哪些疗效呢?由于这儿面出现了两个同样的字符,我们还是通过事例来看一下:
[roc@roclinux 20160229]$ sed 'y/ee/ie/' mysed.txt Biijing 2003 Biijing 2004 Biijing 2005 Biijing 2006 Biijing 2007 Biijing 2008
见到了吧,假如source部份出现了重复的字符,则只有第一次出现的对位替换会形成疗效,前面的并不会起作用。其实下边这个反例愈发清晰些:
#原文件内容 [roc@roclinux ~]$ cat mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 #iji到iba的替换中, 只有j到b起到了效果 [roc@roclinux 20160229]$ sed 'y/iji/iba/' mysed.txt Beibing 2003 Beibing 2004 Beibing 2005 Beibing 2006 Beibing 2007 Beibing 2008
通过n动作来控制行的下移有时我们希望实现隔行处理的疗效,例如只需对质数行做某个替换,这时侯,我们就须要n动作的帮忙啦:
#原文件内容 [roc@roclinux ~]$ cat mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 #我们同时使用了n动作和y动作 [roc@roclinux ~]$ sed ‘/200/{n;y/eijng/EIJNG/;}’ mysed.txt Beijing 2003 BEIJING 2004 Beijing 2005 BEIJING 2006 Beijing 2007 BEIJING 2008
你会发觉,小写的BEIJING是隔行出现的。这就是n选项在起作用,它的真实作用是将下一行内容放在处理缓存中,这样,就让当前这一行躲避开了替换动作,是不是有点像小时候玩游戏时通过左右键躲避开BOSS的大招,哈哈。将指定行写入到特定文件中文章要步入尾声了,我们最后再教你们一个特别实用的动作,那就是w动作linux命令passwd,它可以将匹配到的内容写入到另一个文件中,即拿来实现内容的筛选与保存:
#将包含2004、2005、2006的行保存到new.txt文件中 [roc@roclinux ~]$ sed ‘/200[4-6]/w new.txt’ mysed.txt Beijing 2003 Beijing 2004 Beijing 2005 Beijing 2006 Beijing 2007 Beijing 2008 #我们要的内容已经乖乖到碗里来了 [roc@roclinux ~]$ cat new.txt Beijing 2004 Beijing 2005 Beijing 2006
好了,sed的流艺术系列到这儿就全部结束啦,相信你对sed早已有了初步的认识,可以在实战中露双手了。