渔舟唱晚的天空
——welkinwalker的遐想
AWK one-line写的非常之好,前些日子我尝试翻译了一下,对我自己的能力也有了一点提升,最近又看了一下Famous Sed One-Liners Explained,觉得sed的难度比awk有过之而无不及啊,一度非常崩溃,幸好坚持了下去,加上一直在cu的shell版块发帖子提问,在黑哥等人的帮助下,也算马马虎虎看完了,为了造福一下部分像我这种sed菜鸟,我将看过的这些内容翻译一下,请大家批评指正。谢谢!
先进入第一部分:空行,编号,以及文本转换

开始翻译之前我想讲一下sed程序的执行流程,还是举一个例子说明吧
  1. #more file
  2. 123
  3. 456
  4. #sed ‘/5/p’ file
  5. 123
  6. 456
  7. 456 
  8. # sed –n ‘/5/p’ file
  9. 456
复制代码
和awk类似,sed 语句的基本结构也是 sed ‘模式{动作1;动作2}’file 。同样也是匹配模式才执行动作。不过sed中有两个空间大家一定要记住,一个叫pattern space(模式空间),一个叫hold buffer(缓冲区/缓冲空间),sed中的模式匹配的对象只是模式空间,而动作{p,d,n,g..etc}则的对象是模式空间和缓冲空间。和awk一样,sed也是一行一行的读入文本,不过sed在执行命令前,会将文本的行读到模式空间中,然后执行模式{动作}语句,而在执行命令完后,默认sed还是把模式空间的内容打印出来(通过-n 参数可以把最后默认打印模式空间的动作取消)。在上面的例子中,首先sed把123读入到模式空间中,由于模式/5/不匹配123,因此后面动作p(打印当前模式空间的内容)也就不执行了,正如之前说的,sed在读入下一行456之前会执行默认的打印动作p,把123打印出来。继续读下一行456,由于模式/5/匹配456,执行动作p把456打印出来,而后默认又打印了一次456。这就是sed命令的一个基本流程。当然大多数情况下我们只是想要把匹配模式的内容打印出来,这里加一个-n参数就可以了。
Tips:在sed读入下一行前会把模式空间清空,所以当读第二行456的时候,模式空间内的123已经没了。
一、        空行
1.        输出两倍行距文件
  1. #sed ‘G’ file
  2. 123

  3. 456
复制代码
这个例子使用了G命令,这个命令把缓冲空间的内容附加到模式空间,由于没有命令对缓冲空间做操作(只有h,H,x三个命令可以对缓冲空间做操作),所有缓冲空间的内容一直为空,因此只是简单的附加了一个换行符\n在模式空间后面,执行完G以后,sed默认执行打印的动作将123\n打印出来,因此输出的内容里面就多了一个空行。
2.        输出两倍行距文件(文件有空行,非空行之间间隔不超过一个空行)
  1. #more file
  2. 123

  3. 456
  4. #sed ‘/^$/d;G’ file
  5. 123

  6. 456
复制代码
Sed中的只有匹配模式的行才执行动作。这个例子中有两个模式{动作}语句,第一个语句只有当行匹配/^$/的时候才进行操作,^$代表空行大家应该都知道吧,sed对空行执行动作d,这个命令的意思是删除当前模式空间的内容,开始新的循环。怎么理解呢?其实就是把模式空间的空行清空以后,不再执行后面的命令,也不执行默认的打印动作,而是返回到开头,读取下一行的内容到模式空间,继续执行命令。所以说是开始新的循环。简单来说就是读到空行就把它删除,然后重新读取下一行。当sed读到非空行的时候,不匹配模式,因此不执行d,G没有模式限制,因此去执行G,跟例1一样,加一个空行在后面,打印出来,在继续读下一行,因此得到以上输出。
3.        输出3被行距
  1. #sed ‘G;G’ file
复制代码
这个没什么好讲的,两次G,也就是附加两个回车在文本的后面,打印出来。
4.        只打印奇数行文本
  1. #more file
  2. 123
  3. 456
  4. 789
  5. abc
  6. #sed ‘n;d’ file
  7. 123
  8. 789
复制代码
这里出现了一个新的命令n,命令n的作用是:打印当前模式空间的内容(如果前面加了参数-n则不打印),然后清空模式空间,把下一行读入到模式空间中。然后执行d,即删除模式空间内容,在回到开头。所以大家可以发现,打印出来的都是奇数行,而偶数行都被d删除了。
5.        在匹配正则表达式/5/的行的前面插入一个空行
  1. #sed ‘/5/{x;p;x}’ file
  2. 123

  3. 456
  4. 789
复制代码
出现了一个新的命令x,之前讲到x命令可以操作缓冲空间,具体就是把模式空间的内容和缓冲空间的内容交换,模式/5/只匹配第二行的456,因此对第一行和第三行,就是默认打印出来而已,当读入456的时候,x将模式空间内容的456与缓冲空间的内容交换(默认是空),接着把打印模式空间的空行,再执行x,这个时候缓冲空间里有456,又把456还给模式空间,最后执行默认的打印动作,把456打印出来。
Tips:{x;p;x}是一个命令群组,匹配模式才按顺序执行他们。
6.        在匹配正则表达式/5/的行的后面插入一个空行
  1. #sed ‘/5/G’ file
  2. 123
  3. 456

  4. 789
复制代码
这个例子和第一个例子类似,只不过G只对456这行操作,因此只在第二行后面附加一个空行。
7.        在匹配正则表达式/5/所在行的前后两行都加上一个空行
  1. #sed ‘/5/{x;p;x;G}’ file
复制代码
这个例子其实就是5,6的合体,读入456后,先执行x;p打印出空行,然后执行x;G,打印出456和空行,也就是在456的前后各有一个空行。
二、        编号
8.        给文本的每行编号,并把行号放在行的左边
  1. #sed = file|sed ‘N;s/\n/\t/’
  2. 1   123
  3. 2   456
  4. 3   789
复制代码
有一点点复杂了,这个语句其实可以分成两个,第一个使用了新的命令=,作用是直接把当前行的行号打印出来,因为没有办法直接把行号附加到模式空间去,所有才利用管道符号执行第二个sed命令来实现这个功能。第二个sed又有了一个新的命令N,这个命令的作用就是附加一个\n和下一行的内容到当前的模式空间去,同样s///命令也是sed中非常基本的一个命令,s/\n/\t/的作用是如果模式空间内有\n,就把\n换成\t也就是制表符,然后再把模式空间的内容打印出来
我们来看看这两个命令分别执行的过程
  1. #more file
  2. 123
  3. 456
  4. 789
复制代码
执行第一个sed = file后
  1. #sed = file
  2. 1
  3. 123
  4. 2
  5. 456
  6. 3
  7. 789
复制代码
第二个语句是针对第一个语句的输出来做操作的,来看sed ‘N;s/\n/\t/’ ,首先模式空间内容是1,N将换行\n和123附加到了1的后面,因此模式空间就变成了1\n456,s/\n/\t/则把换行符\n换成了制表符\t,由此模式空间就变成了1\t123,然后打印出来,其他依次类推,所以得到了以下内容
  1. 1   123
  2. 2   456
  3. 3   789
复制代码
9.        给文本每行编号,并把行号右对齐。
  1. #sed = file | sed 'N; s/^/     /; s/ *\(.\{6,\}\)\n/\1  /'
复制代码
这个例子也包含了两部分,第一部分跟例8一样给每行编号,第二部分使用命令N把没两行的内容连在一起,然后使用两个替换命令把行号右对齐,第一个替换命令在行的开头加上了5个空格,第二个替换命令在换行符\n前提取至少6个字符,然后把获取的内容和换行符用之前标记的内容\1在这里(\1指的是之前第一个被\(\)括起来的内容,同理第二个被\(\)括起来的内容可以用\2来代替,依次类推。。)和两个空格代替,空格用来把行号和文本分隔开。
  第二部分读起来可能有点难懂,我们看一个例子,为了表达的更清晰,我们用@来代替\n,用-来代替空格。
  1. # echo "-----12@contents" | sed 's/-*\(.\{6,\}\)@/\1--/'
  2. ----12--contents
复制代码
这个正则表达式 ‘-*\(.\{6,\}\)@’ (或者只是 ‘-*(.{6,})@’) 匹配任意个-,然后是6个其他的字符,接着是一个符号@,sed
他们提取出来,并保存起来以供后面的\1调用。首先sed匹配一个-然后是紧接着的六个字符----12和@,接着s命令把之前匹配的内容替换成\1(也就是之前保存起来的六个字符----12)和--.最终的结果就是把”-----12@”变成了”----12”.
10.        只给非空行编号
  1. #more file
  2. 123
  3. 456

  4. 789
  5. # sed '/./=' file | sed '/./N; s/\n/ /'
  6. 1 123
  7. 2 456

  8. 4 789
复制代码
这个例子也是分成了两个部分,第一部分的输出通过管道符|传递给第二部分当做第二部分的输入,第一部分使用正则表达式/./过滤出至少一个字符的行,当sed把空行放入模式空间后,由于不匹配模式,因此也不对其执行=这个编号的命令。第二部分和第八例题一样也是把两行合并成一行后,替换\n为空格,然后打印出来。
11.        计算文件的行数(类似wc –l的作用)
  1. #sed -n '$=' file
  2. 4
复制代码
这个sed例子使用了参数-n去修饰执行的动作,-n使得在模式空间被处理完后,并不执行默认的p把模式空间内容打印出来,想在在-n参数下输出内容,只能使用一些命令(=,a,I,i,p,P,c,r,w..etc),这个例子中,模式部分是$,匹配文件的最后一行,动作也=,也就是打印行号,因此输出是最后一行的行号,也就是行的数量。
三、        文本替换
Sed one-liner中在这里介绍了很多关于windows格式文本转为unix格式文本,大家要知道在windows下面是用两个字符分行即回车+换行,而unix下只有一个换行,cu里相关的内容有很多,我就不加介绍了。
12.        删除每行的空白符(包括空格和制表符)
  1. #more file
  2. 123
  3.     456
  4. 789
  5. #sed ‘s/^[ \t]*//’ file
  6. 123
  7. 456

  8. 789
复制代码
这个很简单,s将每行中匹配行首(^匹配行首)任意个空白的行,并把这些空白删除,仅此而已。
13.        删除每行结尾的空白行
  1. #sed ‘s/[ \t]*$/’ file
复制代码
这个也没什么好讲的,匹配行尾有任意个空白的行,并把空白删除
14.        同时删除行首和行尾的空白
  1. # sed 's/^[ \t]*//;s/[ \t]*$//' file
复制代码
只是两个例子的合体而已。

15.        每行的开头添加两个空白
  1. #more file
  2. 123
  3. 456
  4. 789
  5. #sed ‘s/^/  /’ file
  6.   123
  7.   456
  8.   789
复制代码
在行首的位置加上两个空白,仅此而已。
16.        右对齐文本(文本宽度为21个字符)
  1. # sed -e :a -e 's/^.\{1,20\}$/ &/;ta' file
  2.                  123
  3.                  456
  4.                  789
复制代码
这个例子中sed出现了一个新的参数-e,-e的作用是允许sed把一段语句分成若干部分,当sed执行命令前,会先将这些部分组合起来,再执行命令。我们通常把一段sed分成若干部分是因为这些部分分别完成不同的功能,分开后比较容易读懂。第一个部分的命令之前大家也没有见过,是一个冒号和a,作用是创建一个名字叫a的标签。第二部分sed使用了一个新的命令t,t的作用是如果前一个s/http://www.cnblogs.com/命令执行成功,那么sed将跳转到指定的标签,这里ta也就是跳转到之前的标签a这里,这个:a .s/http://www.cnblogs.com/.ta,构成了一个循环,也就是说只要模式空间的内容能够执行s/http://www.cnblogs.com/替换命令,sed就通过t把替换后的文本再重新执行替换,周而复始,直到模式空间的内容不满足s/http://www.cnblogs.com/的匹配要求,才终止循环,打印出模式空间的内容。
   下面来看一下替换命令s/^.\{1,19\}$/ &/,其中^.\{1,19\}$匹配包含1个或19个字符的行,后面的&则是代表前一个模式中的内容,也就是.\{1,19\},简单说就是,当模式空间的内容是1个或19个字符的时候,就在模式空间的内容前面加上一个空格,如果前面的循环大家看的懂的话,就可以可以看懂这个例子了:就是把每行的内容前面加上一个个的空白,直到这行的长度超过了19个字符,当文本宽度是20个字符的时候,sed就不再加空格了,直接打印出文本。
   类似一个while循环
  1. # while (str.length() <= 21) {
  2. str = " " + str
  3. }
复制代码
17.        文本居中(宽度为21字符)
  1. # sed  -e :a -e 's/^.\{1,20\}$/ & /;ta' file
  2.          123         
  3.          456         
  4.          789  
复制代码
这个例子很前一个几乎一样,不同的是在添加空格的时候,左右都添加了,当文本的长度达到21个字符的时候,前后的空白字符的个数也一样,也就达到了文本居中的目的了。
18.        替换文本每行中第一次出现的1为a
  1. #more file
  2. 123123123
  3. 456
  4. 789
  5. #sed ‘s/1/a/’ file
  6. a23123123
  7. 456
  8. 789
复制代码
一个简单的替换语句,把文本中每行的第一个1替换成a
19.        替换每行出现的第二个1为a
  1. #sed ‘s/1/a/2’ file
  2. 123a23123
  3. 456
  4. 789
复制代码
其实这才是替换语句的完成格式,把每行中出现的第二个1替换成a,没有这个2的话,sed默认为1,也就是上一题的匹配第一个出现的1
20.        把所有行中的1替换成a
  1. #sed ‘s/1/a/g’ file
  2. a23a23a23
  3. 456
  4. 789
复制代码
这里使用了另一个位置参数g,代表所有,也就是把所有的1都替换成a
21.        如果一个行出现了2个1,则替换第一个1为a
  1. #more file
  2. 123123
  3. 4561
  4. 789
  5. #sed ‘s/\(.*\)1\(.*1\)/\1a\2/’ file
  6. a23123
  7. 4561
  8. 789
复制代码
作用大家都很清楚了,只是在s替换语句中出现了2个组\(..\),第一个组里包含了在第一个1前面的所有字符,而第二个组里包含了从第一个1后到第二个1截止(包含第二个1)的所有字符。因此这个替换语句的模式中包含了2个1,但只是替换第一个1为a,这也是为什么在第二行中也有1,为什么不会被替换成a的原因,因为第二行只有一个1,不匹配s替换语句中的模式。
22.        替换每行中最后一次出现的1为a
  1. #sed ‘s/\(.*\)1/a/’ file
  2. 123a23
  3. 4561
  4. 789
复制代码
同样使用了字符组,匹配的是1前面的所有字符,之所以会把最后出现的1替换成a,是因为.*是最大匹配,比如说在第一行123123中,.*1能匹配1,和1231,但是默认匹配最大也就是1231,因此替换的是最后一个1.
23.        在包含6的行中把所有1都替换成a
  1. #sed ‘/6/s/1/a/g’ file
  2. 123123
  3. 456a
  4. 789
复制代码
改例子使用了一个正则表达式/6/去限制替换命令的使用,也就是说只有匹配6的行才能够执行替换。
24.        在不含6的行中把所有1都替换成6
  1. #sed ‘/6/!s/1/a/g’ file
  2. a23a23
  3. 4561
  4. 789
复制代码
Sed可以使用反向匹配,也就是不匹配的行执行动作,在这里,不匹配6的第一行中的1都被换成了a,第二行中有6,所以不把1换成a
25.        替换1或者6或者9为a
  1. #sed ‘s/1/a/g;s/6/a/g;s/9/a/g’ file
  2. a23a23
  3. 45aa
  4. 78a
复制代码
这里使用了3个s替换语句去匹配和替换。如果你用的是gnu版本的sed,就可以用下面的语句
  1. #sed ‘s/1|6|9/a/g’ file
  2. a23a23
  3. 45aa
  4. 78a
复制代码
Sed提供了更高级的正则表达式功能包含了间隔符|,这里的1\|6\|9就是表示匹配1或者6或者9
26.        倒序文本(类似tac的作用)
  1. #more file
  2. 123
  3. 456
  4. 789
  5. #sed ‘1!G;h;$!d’ file
  6. 789
  7. 456
  8. 123
复制代码
终于到了一个稍微有点难度的例子了,首先我们来解释一个这个命令,G:前面讲过,就是把缓冲区的内容附加在模式空间的后面(以\n分隔)。h:将模式空间的内容把缓冲区的内容覆盖,这时候缓冲区的内容和模式空间一样了d:当然就是把模式空间的内容删除,并返回到开头。我们来逐行看一下
第一行:1!G的意思是出了第一行其他行都执行G,因此跳过,直接到h,把模式空间的内容拷到缓冲区中,缓冲区中的内容是123接着执行d,返回到了开头,继续读下一行456
第二行:第二行可以执行G命令,即把缓冲区123的内容附加到模式空间中456的后面,并以\n分隔,因此模式空间的内容为456\n123,h后,缓冲区的内容也变成了456\n123,同样d后,什么都不输出直接到下一行
第三行:执行G,附加缓冲区的456\n123到789的后面,及模式空间变成789\n456\n123,同时缓冲区通过h也变成了789\n456\n123,最后的$!d的意思是最后一行不执行d的动作,也就是命令到此结束了,sed默认把模式空间的789\n456\n123打印出来,也就是大家看到的结果了,下面的流程可以帮助大家理解。
读入文本        命令        模式空间                      缓冲空间        打印结果
123        1!G        123                              空                   空
        h        123                             123                        空
        $!d        空                      123                        空
456        1!G        456\n123                            123                        空
        h        456\n123                             456\n123        空
        $!d        空                      456\n123        空
789        1!G        789\n456\n123            456\n123        空
        h        789\n456\n123           789\n456\n123        空
        $!d        789\n456\n123           789\n456\n123        789\n456\n123
最后打印出来的789\n456\n123也就是我们要的结果了。
另一种写法
  1. # sed -n '1!G;h;$p' file
  2. 789
  3. 456
  4. 123
复制代码
-n防止sed默认的p动作,而只在最后一行的时候把模式空间的东西打印出来
指的一提的是,这个例子会在执行的过程中会使用大量的内存,因为它在打印出倒序的文本之前把整个文件的内容都保存在缓冲区里面,所以如果文件的行数过多的话,还是不要使用这个语句吧。
27.        翻转每行的内容(类似rev的作用)
  1. # sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' file
  2. 321
  3. 654
  4. 987
复制代码
这个命令的结构非常复杂,可以把它分成4个部分
  1. #sed '
  2. /\n/!G
  3. s/\(.\)\(.*\n\)/&\2\1/
  4. //D
  5. s/.//
  6. '
复制代码
我们一个个来分析,以第一行123为例
/\n/!G:如果模式空间的内容不包括\n,把缓冲区的内容附加到模式空间后,以\n分隔,缓冲区的内容为空除非有命令对其进行操作,这样执行过后模式空间的内容变成123\n
s/\(.\)\(.*\n\)/&\2\1/:s替换的模式部分包含了2个字符组,字符组1只包含了1个任意字符,第二个字符组包括了剩余的字符和\n,&代表的是前面整个匹配项,也就是123\n,例如,在执行完这个语句后,模式空间的内容123\n就变成了123\n23\n1
//D:这个语句是整个sed例子的关键,一个空的匹配//,表示匹配上一个出现的正则表达式,这里也就是/\(.\)\(.*\n\)/D了,D的作用是删除模式空间中从开始到第一个\n截止的字符,并从第一个命令开始重新执行sed(不读到下一行)。实际上是创建了一个循环,也就是只要模式空间的\n前面有一个字符,就把\n和前面的字符删除,剩余的内容传递到第一个命令继续执行,只有\n前面没有字符了,循环才结束。
S/.//:意思很简单,删除模式空间的第一个字符,但是这个命令执行的条件就是D不执行,也就是说模式空间中\n前面没有字符,后面后经过翻转后的内容,其实就是把\n给删除了,接着默认sed输出翻转后的内容,还是来看一下流程吧
读入文本                 命令                    模式空间               缓冲空间                  打印结果
123                    /\n/!G                         123\n                            空                              空
               s/\(.\)\(.*\n\)/&\2\1/          123\n23\n1                                          空
                  //D                           23\n1                           空                             空
        D执行成功,循环到开头执行/\n/!G                        
                  /\n/!G                                23\n1            空                            空
        s/\(.\)\(.*\n\)/&\2\1/                              23\n3\n21            空                              空
                  //D                               3\n21           空                              空
        D执行成功,循环到开头执行/\n/!G 
                    /\n/!G                                 3\n21           空                               空
         s/\(.\)\(.*\n\)/&\2\1/            3\n\n321           空                               空
                        //D                                \n321          空                               空
            D执行成功,循环到开头执行/\n/!G                
                         /\n/!G              \n321                          空                                空
                   s/\(.\)\(.*\n\)/&\2\1        \n321          空                               空
                             //D                 \n321          空                                空
        模式不匹配,开始执行s/.//                   321        空                               321
把321打印出来了,累死我了。。
28.        把文本两行合成一行
  1. #more file
  2. 123
  3. 456
  4. 789
  5. abc
  6. #sed ‘$!N;s/\n/ /’ file
  7. 123 456
  8. 789 abc
复制代码
这个例子使用N将两个连续的行组合成一个新行,他们之间通过\n连接,因此第二个替换语句将\n换成空格,就得到了输出,由于最后一行没有下一行可以连接,所以N的前面是$!
29.        如果行的结尾是\,就把下一行附加到这一行末尾。
  1. #more file
  2. 123\
  3. 456\
  4. 789
  5. abc
  6. #sed –e :a–e ‘/\\$/N;s/\\\n/ /;ta’
  7. 123 456 789
  8. abc
复制代码
第一个命令:a,创建了一个标签a,而第二个命令判断模式空间的内容是否是以\结尾,如果是,则执行N把\n和下一行附加到这行的结尾,然后执行s替换,把中间的\\n换成空格,如果成功,则ta把模式空间的内容循环到标签的位置继续处理,也就是判断附加的那行是否还是以\结尾,如果是,继续附加,循环下去。如果不是,打印出模式空间的内容。
Tips:如果没有这个循环的话,就不能检查每一行的结尾是否是\.
30.        如果行的开头是=,就把这行附加到上一行的结尾。
  1. #more file
  2. 123
  3. =456
  4. =789
  5. abc
复制代码
  1. #sed –e :a –e ‘$!N;s/\n=/ /;ta’ –e ‘P;D’ file
  2. 123 456 789
  3. abc
复制代码
这个例子的开头也创建了一个标签a,然后检测文本是不是最后一行,如果不是就把下一行附加到这一行的结尾,以\n分隔,如果正好下一行的开头是=,则使用替换命令s把换行符\n和=替换成一个空格,如果替换成功,则ta把命令循环至标签a的位置,然后继续附加下一行,检查下一行是否是以=开头,是的话就替换,依次循环,知道下一行的开头不是=,则循环结束,开始执行后面的命令P;D,P的意思是打印模式空间中从一个字符到第一个\n为止的所有字符,D的意思是删除第一个字符到\n截止的所以字符,其实也就是删除刚才打印过的字符,然后回到开头。继续读下一行
        上面的例子中,第一行和第二行第三行之所以连在了一起,就是因为第二行和第三行是以=开头。
31.        将数字组以千分位的方式分成串
  1. #echo "1234567"|sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta'
  2. 1,234,567
复制代码
这个例子首先创建一个标签a,然后模式替换部分分成了两个组,第一个组在最后3个数字之前是任意个字符加上一个数字,第二个组是最后的三个数字,替换的结果是在两组之间加上一个逗号,然后又是循环开始,知道所有的数字都3个一组的被逗号分隔。
   看看上面的例子,第二个组里包含的是数字1234,第二个组里包含的是567,加上逗号后变成1234,567
由于替换成功,循环开始,这次第一个组里包含的是1,第二个组里包含的是234,替换过后,1234,567就变成了1,234,567,接着循环,由于1,234,567中没有连续的四个数字,所有替换不成立,sed默认打印出模式空间的内容,也就是1,234,567。
  如果sed的版本是gnu的,则可以简写成
  1. #echo "1234567"|sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
  2. 1,234,567
复制代码
不同的地方在于包含3个数字的字符组是如何匹配的。重点在于这个\B,它是一个位置字符,不占空间,匹配任何地方但是不包含字符分界线如空格,分号,逗号,冒号等而最后的\>,匹配的是单词的分界如逗号。

32.        每2行加一个空行
  1. #more file
  2. 123
  3. 456
  4. 789
  5. abc
  6. #sed ‘n;G’ file
  7. 123
  8. 456

  9. 789
  10. abc
复制代码
前讲过,n命令的作用是打印当前行,然后清空,把下一行读入,G把一个空行加到了下一行的结尾,这样也就是打印了两行之后在打印一个空行了。
GNU版本的sed还有另一种写法
  1. #sed ‘0~2G’ file
  2. 123
  3. 456

  4. 789
  5. abc
复制代码
这个其实也好理解,就是从还没有读入行开始,也就是0行,每过两行就执行一个G,也就是添加一个空行,大家记住这个格式就可以了。
posted on 2011-08-12 14:43  welkinwalker  阅读(1496)  评论(0编辑  收藏  举报