Linux-----sed 命令详解
sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换、删除、新增、选取等特定工作,下面先了解一下sed的用法
sed命令行格式为:
======================================================================================
常用选项:
-n∶使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-e∶直接在指令列模式上进行 sed 的动作编辑;
-f∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;
-r∶sed 的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)
-i∶直接修改读取的档案内容,而不是由萤幕输出。
常用命令:
a ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p ∶列印,亦即将某个选择的资料印出。通常 p 会与参数 sed -n 一起运作~
s ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!
举例:(假设我们有一文件名为ab)
删除某行
[root@localhost ruby] # sed ‘1d‘ ab #删除第一行
[root@localhost ruby] # sed ‘$d‘ ab #删除最后一行
[root@localhost ruby] # sed ‘1,2d‘ ab #删除第一行到第二行
[root@localhost ruby] # sed ‘2,$d‘ ab #删除第二行到最后一行
显示某行
. [root@localhost ruby] # sed -n ‘1p‘ ab #显示第一行
[root@localhost ruby] # sed -n ‘$p‘ ab #显示最后一行
[root@localhost ruby] # sed -n ‘1,2p‘ ab #显示第一行到第二行
[root@localhost ruby] # sed -n ‘2,$p‘ ab #显示第二行到最后一行
使用模式进行查询
[root@localhost ruby] # sed -n ‘/ruby/p‘ ab #查询包括关键字ruby所在所有行
[root@localhost ruby] # sed -n ‘/^ruby/p‘ ab #查询包括关键字ruby所在起始的所有行
[root@localhost ruby] # sed -n ‘/ruby$/p‘ ab #查询包括关键字ruby所在结尾的所有行
[root@localhost ruby] # sed -n ‘/^$/=‘ ab #查询‘空行’的所在行号
[root@localhost ruby] # sed -n ‘/^[[:space:]]*$/p‘ ab#查询内容为多个空格/tab组成的行
[root@localhost ruby] # sed -n ‘/\$/p‘ ab #查询包括关键字$所在所有行,使用反斜线\屏蔽特殊含义
增加一行或多行字符串
[root@localhost ruby]# cat ab
Hello!
ruby is me,welcome to my blog.
end
[root@localhost ruby] # sed ‘1a drink tea‘ ab #第一行后增加字符串"drink tea"
Hello!
drink tea
ruby is me,welcome to my blog.
end
[root@localhost ruby] # sed ‘1,3a drink tea‘ ab #第一行到第三行后增加字符串"drink tea"
Hello!
drink tea
ruby is me,welcome to my blog.
drink tea
end
drink tea
[root@localhost ruby] # sed ‘1a drink tea\nor coffee‘ ab #第一行后增加多行,使用换行符\n
Hello!
drink tea
or coffee
ruby is me,welcome to my blog.
end
代替一行或多行
[root@localhost ruby] # sed ‘1c Hi‘ ab #第一行代替为Hi
Hi
ruby is me,welcome to my blog.
end
[root@localhost ruby] # sed ‘1,2c Hi‘ ab #第一行到第二行代替为Hi
Hi
end
替换一行中的某部分
格式:sed ‘s/要替换的字符串/新的字符串/g‘ (要替换的字符串可以用正则表达式)
[root@localhost ruby] # sed -n ‘/ruby/p‘ ab | sed ‘s/ruby/bird/g‘ #替换ruby为bird
[root@localhost ruby] # sed -n ‘/ruby/p‘ ab | sed ‘s/ruby//g‘ #删除ruby
插入
[root@localhost ruby] # sed -i ‘$a bye‘ ab #在文件ab中最后一行直接输入"bye"
[root@localhost ruby]# cat ab
Hello!
ruby is me,welcome to my blog.
end
bye
======================================================================================
sed可以充当一个行过滤器(与管道相接,从管道上游获得输入),或者从文件中获取其输入。输出将被放入到标准输出流。sed 将输出中的行加载到模式空间(pattern space),对模式空间的内容应用 sed 编辑命令,然后将模式空间写入到标准输出中。Sed 可以在模式空间中组合多个行,然后它可能将输出写入到文件中、只写入选择的输出,或者根本不执行写入。
Sed 使用正则表达式语法在模式空间中搜索并有选择地替换文本,以及决定对哪些文本行应用编辑命令。保持缓存为文本提供了临时存储。保持缓存可以取代模式空间、被添加到模式空间,或者与模式空间进行互换。Sed 提供了一组有限的命令,但是这些命令结合了正则表达式语法和保持缓存,因而实现了某些非常令人吃惊的功能。sed 命令集常常被称为 sed 脚本。
举例说明sed的使用方法:
sed ‘s/a/A/‘ text1 #s命令表示替换,将text1每一行的第一个a替换为A
sed ‘s/a/A/g‘ text1 #加入g标记,表示将替换每一行的所有a
sed ‘2d;$s/a/A/g‘ text1 #2d表示删除第二行,;分隔了两个命令,第二个命令开始的$表示后续命令只操作最后一行
除了操作单独的行外(前面提到的$),sed 还可以操作一个行范围。行的起始和结束由一个逗号(,)分隔,并且可以被指定为行号、正则表达式或表示最后一行的美元符号($)。可以用大括号 { 和 } 对命令进行分组,使在大括号之间的命令只用于按范围选择的行。使用 -e 选项向脚本添加多个命令(实际上就是将命令分开,看起来更清楚,需要注意的事项是分隔开的地方不是任意的)。
sed -e ‘2,${‘ -e ‘s/a/A/g‘ -e ‘}‘ text1 #用-e选项来分段命令,2,$表明行范围,{}圈定行范围内的命令
sed -e ‘/pear/,/bana/{‘ -e ‘s/a/A/g‘ -e ‘}‘ text1 #/pear/,/bana/通过正则表达式指定行范围:从包含pear的行开始到包含bana的行结束(闭区间)
通过选项-f可以从文件读取命令
sed -f sedtab text1 #用sedtab文件中的字符串作为命令充当sed的命令对text1进行操作
sed ‘=‘ text2 #=命令输出行号,但是会将行号新起一行
sed ‘=‘ text2|sed ‘N;s/\n//‘ #使用 N 命令将第二个输入行读取到模式空间,最后删除模式空间中两个行之间的换行符(\n)已经将不明白了,不得不看较全的sed教程
=======================================================================================
sed -e ‘d‘ /etc/services
sed 打开 /etc/services 文件,1将一行读入其模式缓冲区,2执行编辑命令("删除行"),3然后打印模式缓冲区(缓冲区已为空)。然后,它对后面的每一行重复这些步骤。
sed -e ‘1d‘ /etc/services | more #删除第一行
sed -e ‘1,10d‘ /etc/services | more #删除[1,10]行
sed -e ‘/^#/d‘ /etc/services | more #删除以#开头的行
sed -n -e ‘/regexp/p‘ /path/to/my/test/file | more #-n表示除非有p选项在,否则不打印模式空间
sed -n -e ‘/BEGIN/,/END/p‘ /my/test/file | more #打印从包含 "BEGIN" 的行开始,并且以包含 "END" 的行结束的文本块
sed -n -e ‘/main[[:space:]]*(/,/^}/p‘ sourcefile.c | more #打印 C 源文件中的 main() 函数
在开始的时候先说一下和egrep的区别,可以使用扩展正则表达式,但是需要\来进行转义:
? + ( ) { }
‘s///‘ 替换命令只是一个命令还可以与地址一起使用来控制要将命令应用到哪些行
sed -e ‘s/foo/bar/‘ myfile.txt #将 myfile.txt 中每行第一次出现的 ‘foo‘(如果有的话)用字符串 ‘bar‘ 替换,然后将该文件内容输出到标准输出。
sed -e ‘s/foo/bar/g‘ myfile.txt #替换每行中的 所有出现
sed -e ‘1,10s/enchantment/entrapment/g‘ myfile2.txt #用短语 ‘entrapment‘ 替换所有出现的短语 ‘enchantment‘,但是只在第一到第十行(包括这两行)上这样做。
sed -e ‘/^$/,/^END/s/hills/mountains/g‘ myfile3.txt #用 ‘mountains‘ 替换 ‘hills‘,但是,只从空行开始,到以三个字符 ‘END‘ 开始的行结束(包括这两行)的文本块上这样做
sed -e ‘s:/usr/local:/usr:g‘ mylist.txt #使用冒号作为分隔符。如果需要在规则表达式中指定分隔符字符,可以在它前面加入反斜杠
sed -e ‘s/<.*>//g‘ myfile.html #匹配并删除 ‘<‘ 开始、到 ‘>‘ 结束、并且在其中包含任意数量字符的短语(它不会很好地工作)
sed -e ‘s/<[^>]*>//g‘ myfile.html #这样就对了
正则表达式的字符类(这些字符类应该被括在[]中)
[:alnum:] 字母数字 [a-z A-Z 0-9]
[:alpha:] 字母 [a-z A-Z]
[:blank:] 空格或制表键
[:cntrl:] 任何控制字符
[:digit:] 数字 [0-9]
[:graph:] 任何可视字符(无空格)
[:lower:] 小写 [a-z]
[:print:] 非控制字符
[:punct:] 标点字符
[:space:] 空格
[:upper:] 大写 [A-Z]
[:xdigit:] 十六进制数字 [0-9 a-f A-F]
sed -e ‘s/.*/ralph said: &/‘ origmsg.txt #&表示被正则表达式匹配的部分
sed -e ‘s/\(.*\) \(.*\) \(.*\)/Victor \1-\2 Von \3/‘ myfile.txt #实现把 "eeny meeny miny" 替换成 "Victor eeny-meeny Von miny" 的功能
sed -n -e ‘=;p‘ myfile.txt #‘=‘ 命令告诉 sed 打印行号,‘p‘ 命令明确告诉 sed 打印该行(因为处于 ‘-n‘ 模式),分号分隔命令
sed -n -e ‘=‘ -e ‘p‘ myfile.txt #完成上个命令同样的效果
sed -n -f mycommands.sed myfile.txt #处理文件中书写的命令
1,20{s/[Ll]inux/GNU\/Linux/g;s/samba/Samba/g;s/posix/POSIX/g } #所有的行都会通过过滤器,但是只会处理1,20
i\ This line will be inserted before each line #每行前面添一行把一行或多行插入到模式空间中的当前行之后
c\ You‘re history, original line! Muhahaha! #"更改行"命令将实际 替换模式空间中的当前行
sed -e ‘s/$/\r/‘ myunix.txt > mydos.txt #将UNIX 风格的文本转换成 DOS/Windows 格式。基于 DOS/Windows 的文本文件在每一行末尾有一个 CR(回车)和 LF(换行),而 UNIX 文本只有一个换行
sed -e ‘s/.$//‘ mydos.txt > myunix.txt #将dos/windows风格文本风格变成unix风格,注意.$表示行末前的那个字符,当然就是那个\r了,然后替换为无物,就是删除
sed -e ‘1!G;h;$!d‘ forward.txt > backward.txt #实现反转行,即是tac的功能,解释如下:
如果把模式空间命名为M,保留空间命名为R,当前输入行命名为NL,那么做的功能(用伪代码表示)就是:
while has new input//一次读入一行(sed默认操作)
M = NL;//从标准输入读入的一行赋值给模式空间(sed默认操作)
if NL is not the first line//如果不是第一行
M += R;//将保存空间附加给模式空间
R = M;//将模式空间赋值给保存空间
if NL is not the last line//如果不是最后一行
M = emptyline;//清空模式空间,实际上是赋值为一个空行(空行就是清空d的操作)
print M;//输出模式空间(sed默认操作)
R的初始值应该是一个空行
=================================================================================
文件空行处理
1. 在文件中的每一行后面添加一个空行。
sed ‘G‘ test.txt
解释: Get命令是将保留空间的内容取出,并添加到当前模式空间的内容之后(添加一行)。当保留空间为空时,效果为往模式空间添加一行空行。
2. 保证文件中的每一行后面都有一行空行。和1不同的是,如果文件中本身包含空行,则合并成一行。
sed ‘/^$/d;G‘ test.txt
解释:首先删除空行,再添加一行空行。
3. 删除偶数行
sed ‘n;d‘ test.txt
解释:n的意思读入下一行,并且输出当前行。当n读入下一行之后,用d将其删除。
4. 在匹配regex的行之前添加空行
sed ‘/regex/{x;p;x}‘ test.txt
解释:x的意思是交换保留空间和模式空间的内容,首先保留空间为空,首次交换并用p打印空行;接着将原有内容交换回来,执行到命令末尾,自动输出模式空间的内容。
5. 在匹配regex的行之后添加空行
sed ‘/regex/G‘ test.txt
解释:参考1
6. 在匹配regex的行之前和之后都添加空行
sed ‘/regex/{x;p;x;G;}‘ test.txt
解释:参考4、5
7. 每五行后添加一行空行
sed ‘n;n;n;n;G‘
或者
sed ‘0~5G‘ test.txt
解释:很简单,每次读5行,再添加一个空行。第二种方法利用了GNU Sed的功能 addr~step,查看man sed。
===================================================================================
文件行号处理
1. 给每一行添加行号,并且行号与行的非空白内容之间以制表符(t)分隔(保证左对齐)
类似:
1 aaa 20 aaa
相应的命令如下:
sed ‘=‘ test.txt | sed ‘N;s/s*ns*/t/‘
解释:首先要取出并打印行号,可以用=命令打印行号,但是此时行号与行内容不在同一行输出,因此需要将标准输出重定向再次使用sed命令处理。使用Next命令读入下一行,并将n(包括多余的空白)替换成一个制表符(t),再默认输出打印。准确地说,这里使用了两条sed命令。
2. 给每一行添加行号,并且行号与行的非空白内容之间以制表符(t)分隔(保证右对齐)
类似:(假设行号最多是3位数)
1 aaa 20 aaa 123 aaa
相应的命令如下:
sed ‘=‘ test.txt | sed ‘N; s/^/ /;s/ *([ 0-9]{3})s*ns*/1t/‘
解释:前面同1,这里只介绍后面这部分:s/^/ /;s/ *([ 0-9]{3})s*ns*/1t/
这里首先在行首插入两个空格,然后将空格与后面的行号(数字)部分,只保留三个字符。最后将回车与多余的空白替换成制表符。
3. 给文件每一行加上行号,但是仅当行非空时才打印行号。
sed ‘/./=‘ test.txt | sed ‘/./N; s/s*ns*/t/‘
解释:在sed中.不匹配n,因此用/./匹配非空行,其它同1。 但是如果要处理空行(包含空白符等的行),则需要:
sed ‘/[^[:blank:]]/=‘ test.txt | sed ‘/[^[:blank:]]/N; s/n/t/‘
4. 统计行数
sed -n ‘$=‘ test.txt
解释:使用-n阻止默认输出,并只在最后一行的时候打印行号。
=====================================================================================
文本内容转换和替换
1. 在Unix环境下,转换DOS换行符为Unix格式
sed ‘s/^M//‘ test.txt
解释:^M的键入方法,按住ctrl+v再敲回车。 这种处理和环境依赖性比较大,不是非常统一,这里只介绍一种。
2. 删除行首和行尾空白
sed ‘s/^[[:blank:]]*|[[:blank:]]*$//‘ test.txt
解释:这里再次用到了posix字符组,不多解释。
3. 对每一行按照79列宽处理, 保持右对齐
类似
...................a .................bba ................cccc
(超出的部分不处理)
sed -e ‘:a‘ -e ‘s/^.{1,78}$/ &/;ta‘ test.txt
解释: 对单个命令本身不解释了,这里用到了标签、跳转、替换等命令。 替换过程对不小于79列宽的行处理,在行首插入一个空格,直到等于79列宽为止,自动
输出。
4. 对每一行按照79列宽处理,保持居中。
sed -e ‘:a‘ -e ‘s/^.{1,77}$/ & /; ta‘ test.txt
解释:同3
5. 在每一行用bar替换foo
a. sed ‘s/foo/bar/‘ test.txt b. sed ‘s/foo/bar/4‘ test.txt c. sed ‘s/foo/bar/g‘ test.txt d. sed ‘s/(.*)foo(.*foo)/1bar2/ test.txt e. sed ‘s/(.*)foo/1bar/‘ test.txt
解释:a在一行中只替换一次(首次出现);b替换第四次出现;c全局替换;d替换倒数第二个匹配;e替换最后一个匹配 。
6. 在包含或者不包含baz的行中替换foo为bar
sed ‘/baz/s/foo/bar/g‘ test.txt
sed ‘/baz/!s/foo/bar/g‘ test.txt
7. 反转文件行的顺序(类似tac命令,即从最后一行到第一行的顺序打印)
sed ‘1!G;h;$!d‘ test.txt
解释:首先1!G表示将除第一行之外,都先从保留空间取出内容并追加到模式空间的最后;h表示将模式空间的内容全部覆盖到保留空间;然后 $!d表示将除最后一行之外的,都要将模式空间清除,并从头开始(不打印)。这些命令合起来就是,首先将一行的内容拷贝到临时缓冲区(保留空间),然后清除当前行(不打印),再读入下一行并从缓冲区取会保存的内容,因此行的顺序就颠倒了。
8. 反转文件中每一行的字符顺序(类似rev命令)
sed ‘/n/!G;s/(.)(.*n)/&21/;//D;s/.//‘
解释:首先解释一下这里使用到的一些特殊语法,//D,//为无内容,这是一种简写情况,默认使用上一次使用的正则表达式,这里就是(.)(.*n),因此等价于/(.)(.*n)/D。这条sed命令中过程是这样的,首先该行如果不包含回车,则在末尾添加一个,对应命令中的/n/!G;然后开始替换,目的是把当前最前面的字母放到后面。
例如123n变成123n23n1;23n1变成23n3n21。然后使用D命令删除第一行的内容。最后一个替换去掉首字符。该例子可以自己使用一个简单的例子演练一遍就清楚了。
9. 将两行合并成一行(类似paste命令)
sed ‘$!N;s/n/ /‘ test.txt
解释:$!N表示除最后一行外,其它每行在读入的时候,都将下一行读进来添加到后面。接着用替换命令替换回车为空格。如果$!N改成N在这里不会出现问题,但是要记住的是,当到最后一行时,执行N命令将不会再读入新行,结果是sed退出。不会执行接下来的命令。
10. 如果一行以“”结束,则合并下一行内容到当前行之后。
sed -e ‘:a‘ -e ‘/$/N; s/n/ /; ta‘ test.txt
解释:同8类似,但是要考虑合并多行,因此需要做循环处理,这里使用标签来达到这个目的。
11. 如果一行以等号开始,则合并这一行至上一行,并替换等号为空格
sed -e ‘:a‘ -e ‘$!N;s/n=/ /;ta;P;D‘ test.txt
解释:同9类似,不过这里要读入下一行之后,判断‘n=‘则替换成空格, 如果替换成功,则继续读入下一行(标签跳转);否则, 打印并删除模式空间中的第一行。
D命令不会导入新的行读入。
12. 给数字串加逗号,例如把“1234567”变成“1,234,567”
sed -e ‘:a‘ -e ‘s/([0-9])([0-9]{3})($|,)/1,2/;ta‘ test.txt
或者
sed -e ‘:a‘ -e ‘s/(.*[0-9])([0-9]{3})/1,2/;ta‘ test.txt
解释:这里要使用标签进行循环处理,关键点在正则表达式的书写上。第二种写法更加简练。
13. 给带有小数点和铅的数字加上逗号
sed ‘:a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/12,3/g;ta‘ test.txt
或者
sed ‘:a;s/^(-?[0-9]+)([0-9]{3})/1,2/g;ta‘ test.txt
解释:同11,要注意负号和小数点,因此要加上开始标记^和-。
=======================================================================================
选择性输出行
1. 打印一个文件的前10行(类似head命令)
sed -n ‘1,10p‘ test.txt
或者
sed ‘10q‘ test.txt
解释:显然第二种方法比第一种方法效率高。q退出命令,表明在第10行的时候自动退出,不再读入新的输入行。
2. 打印一个文件的第一行。
sed ‘q‘ test.txt
解释:同上,在读入第一行之后就退出,但是仍打印第一行的内容。
3. 打印一个文件的倒数10行(类似tail命令)
sed ‘:a;$q;N;11,$D;ba‘
解释:如果只看 ‘:a;$q;N;ba‘,效果就是一直将下一行追加到模式空间,最后达到最后一行的时候退出,并打印模式空间的内容。但是当变成‘:a;$q;N;11,$D;ba‘,11,$D表示如果行超过10行,则将模式空间的第一行删除,同时ba跳转到开头,再次读入下一行,保持模式空间的行数在10行。这样看起来就是模式空间的最前面的一行被删除,同时将新的一行追加到末尾处,当循环结束时,模式空间中保存的就是文件的最后10行。
4. 打印一个文件的倒数两行(类似tail -2)
sed ‘:a;$q;N;3,$D;ba‘
或者
sed ‘$!N;$!D‘ test.txt
解释:第一种方法同3一样。第二种方法,$!的意思是不在最后一行上执行命令。N命令不解释,D命令是删除模式空间的第一行,并且跳转到命令开头重新执行,并且当模式空间仍有内容时,不读入新的输入行。这一句的意思透露出两点:
1) D命令之后的命令不会执行,而是跳转到开头,同时也不会自动输出当前模式空间的内容。
2) 模式空间不为空,则不会自动读入下一行的数据,除非使用N命令读入下一行。
因此,$!N;$!D,将下一行读入模式空间,并且将模式空间的第一行删除,除非遇到最后一行,因此当循环结束时,模式空间中包含倒数两行,完成要求,打印输出。
5. 打印一个文件的最后一行(类似tail -1)
sed ‘:a;$q;N;2,$D;ba‘ test.txt
或者
sed -n ‘$p‘ test.txt
或者
sed ‘$!d‘ test.txt
6. 打印匹配“regex”行(类似grep)
sed -n ‘/regex/p‘ test.txt
或者
sed ‘/regex/!d‘ test.txt
解释:同5类似
7. 打印不匹配“regex”行(类似grep -v)
sed -n ‘/regex/!p‘ test.txt
或者
sed ‘/regex/d‘ test.txt
解释:同6。
8. 打印匹配“regex”之前的那一行。
sed -n ‘$!N;/regex/!D;/regex/P‘
或者
sed -n ‘/regex/{g;1!p;};h‘
解释:第一方法理解起来比较简单,读入下一行到模式空间,并且判断是否包含regex,如果匹配,则打印模式空间中的第一行,如果不匹配,则删除模式空间的第一行,循环处理。(这种方法有问题吗?)
第二种方法,如果没遇到匹配行,则将当前行拷贝到保持空间,然后读入下一行,如果匹配,则将保存的行从保持空间中提取到模式空间,并且打印(假如第一行就匹配则不打印)。
9. 打印奇数行
sed -n ‘N;P‘ test.txt
或者
sed -n ‘1~2p‘ test.xt
解释:第一种方法,N读入下一行到模式空间,P打印模式空间中的第一行,然后自动输出被关闭,进入下一次循环,重新读入新的一行到模式空间(自动读入新行,非N,因此模式空间的内容被清除再读入新行),再执行N;P,同样打印模式空间的第一行。效果等同于打印奇数行。第二种方法,比较简单,不过用到GNU Sed的特殊地址表示方法,addr~step,因此只在1,3,5,7等奇数行才打印行的内容。
10. 打印匹配“regex”那一行的后一行。
sed -n ‘/regex/{n;p}‘ test.txt
解释:如果找到匹配的行,则读取下一行,并且打印输出。
11. 打印匹配“regex”那一行的前后一行,并且打印匹配行的行号(类似grep -A1 -B1)
sed -n ‘/regex/{=;x;1!p;g;$!N;p;D;}; h‘ test.txt
解释: 如果不匹配,则先把该行保存到保持空间暂时记录下来;如果找到匹配行,则打印该行的等号,并且将模式空间的内容和保持空间的内容交换,随即打印模式空间的内容(第一行除外,同10);交换之后,再次将保持空间的内容恢复到模式空间(即当前匹配行),再读入下一行(注意$!N),打印模式空间的所有内容(非P),打印完之后,清除模式空间的第一行的内容。进入下一个循环。注意此时,保持空间同样保存着当前的输入行。
12. 假设段落以空行分隔,打印包含“regex”的段落。
sed ‘/./{H;$!d};x;/regex/!d‘ test.txt
sed ‘/./{1h;1!H;$!d};x;/regex/!d‘ test.txt
解释:思路很简单,首先将读入段落的内容,并依次将段落的第一行追加到保持空间备份,然后在保持空间中查找匹配单词。但是第一种方法的输出结果会在开始处多一个空行,第二种方法的目的是去掉多输出的一个空行。
13. 打印长于65个字符的行
sed -n ‘/^.{65}/p‘ test.txt
解释:正则表达式的应用。
14. 打印第52行
sed ‘52q;d‘ test.txt
解释:效率比一般方法高
15. 从第三行开始,每隔7行打印机一行
sed -n ‘3~7p‘ test.txt
sed -n ‘3,${p;n;n;n;n;n;n;}‘ test.txt
解释:比较简单
====================================================================================
选择性删除某些行
1. 删除文件中连续并且重复的行,只保留第一行(类似uniq命令)
sed -n "$!N;/^(.*)n1$/!P;D‘ test.txt
解释:读入下一行,然后用正则判断两行是否一样,如果一样,则不打印,并且删除同样行中的第一行,再循环处理。
2. 删除文件中重复的,但不连续的行,注意不要溢出保持空间的缓冲区大小。
不知道
3. 删除一个文件中前10行
sed ‘1,10d‘ test.txt
解释:比较简单
4. 删除一个文件中最后1行
sed ‘$d‘ test.txt
5. 删除一个文件中最后2行
sed ‘N;$!P;$!D;$d‘ test.txt
解释:使用N读入一行,并且如果新读入的下一行不是最后一行,则打印模式空间中的第一行,并且删除;如果新读入的一行是文件的最后一行,则删除模式空间中的所有内容(即倒数两行)。
6. 删除一个文件中最后10行;
sed ‘:a;$d;N;11,${P;D};ba‘ test.txt
sed ‘:a;$d;N;2,10ba;P;D‘ test.txt
sed -n ‘:a;1,10!{P;N;D};N;ba‘
解释:第一种方法参考前面的打印文件的最后10行内容。第二种方法,首先不停读入下一行的内容,直到读入第11行,此时模式空间中包含11行,打印第一行的内容并删除,然后判断最后读入的那一行是不是最后一行,如果是,则删除模式空间中的内容(一共10行,即倒数10行);如果不是,则继续读入下一行,打印模式空间中的第一行并删除。循环直到最后一行为止。第一种方法,首先将读入前10行的内容,如果读到第10行之后(11行开始),首先打印模式空间的第一行,并读入下一行,再删除第一行,循环处理;始终保证模式空间中包含10行的内容,当在最后一行之后,再读新行会导致sed退出,并打印模式空间的内容。
7. 每8行删除1行
sed ‘0~8d‘ test.txt
解释:比较简单。
8. 删除所有空行
sed ‘/^$/d‘ test.txt
或者
sed ‘/./!d‘ test.txt
解释:都比较简单,第一个匹配空行,第二个匹配非空行。
9. 压缩文件中的连续空行为一行,包括文件开头和结尾(类似cat -s)
sed ‘/^$/N;/n$/D‘ test.txt
解释:遇到空行,则继续读入下一行,如果读入的一行依然是空行,则删除第一行(空行),循环处理。
10. 删除文件中的连续空行,但保留前两个空行
sed ‘/^$/N;/n$/N;//D‘ test.txt
解释:同9,不过不是压缩空行为一行,而是两行,因此在9的基础上再加一步,//D中正则为空,默认使用上次的正则表达式。
11. 删除文件开头的空行
sed ‘/./, $!d‘ test.txt
解释:删除第一行非空行之前的所有空行。
12. 删除文件结尾的所有空行
sed ‘:a;/^n*$/{$d;N;ba}‘ test.txt
解释:如果碰到一个空行,如果不是最后一行,则继续读入下一行,跳到开头,判断模式空间内是否全是空行。如果读到最后一行,而且,模式空间内的内容都是空行,则删除,这意味着删除了所有结尾处的空行。
13. 删除每个段落的最后一行
sed -n ‘/^$/{p;h;};/./{x;/./p}‘ test.txt
解释:如果遇到空行,则直接打印,并且将空行保存到保持空间,这样会覆盖空行的上一行内容,如果上一行不为空行,内容就不打印了,而如果上一行是空行,因为之前已经打印了,所以这里不会有影响;如果不是空行,则交换保持空间和模式空间的内容,保持空间保存的是上一行的内容,如果上一行不是空行,则打印。
=========================================================================================