Sed用法及习题精选
Sed工作原理
-
原理
- 读入新的一行内容到模式空间(pattern space);
- 从指定的操作指令中取出第一条指令,判断是否匹配pattern;
- 如果不匹配,则忽略后续的编辑命令,回到第2步继续取出下一条指令;
- 如果匹配,则针对缓存的行执行后续的编辑命令(补充:执行完后,才进行默认输出[可以被-n选项抑制掉],然后再清空模式空间);完成后,回到第2步继续取出下一条指令;
- 当所有指令都应用之后,输出缓存行的内容;回到第1步继续读入下一行内容;
- 当所有行都处理完之后,结束;
-
命令格式
syntax:sed [option]… {Script} [FILE]…**
-
常用格式
sed 选项 地址编辑命令 文件
-
[option]
-n : 不输出模式空间中的内容至屏幕,即关闭不能被模式匹配到的行到标准输出
-e : 多想编辑命令一次执行
-f FILE : 将编辑指令写入文件,调用FILE
-r : 支持扩展正则表达式元字符
-i : 直接修改原文件
-i.bak : 修改源文件,但是会生成备份文件为.bak的文件
-
地址
-
空地址:即对全文进行处理
-
单地址(line-address)
-
步进地址表示法
1~2 : 所有奇数行: sed -n ‘1~2p’ test
2~2 : 所有偶数行: sed -n ‘2~2p’ test -
地址对(address)
N,M : 第N到M行
N,+M : 从N行向下M行
N,/pattern/ : 从N到正则匹配到的行
/pattern1/,/pattern2/ : 从模式1到模式2匹配到的行
$ : 表示最后一行
-
-
模式空间(基础命令)
-
d : 删除模式空间内容
-
[line-address]a\STRING : append,在指定行下一行追加内容
-
[line-address]i\STRING : insert,在指定行上一行追加内容
-
c\STRING : change,改变指定行内容
-
p : print,打印模式空间的内容
-
l : list,输出行控制符
-
= : 输出行号
-
s/RegExp/REPLACE/g : search,搜索与替换,"/"可以换成其他符号:#@%…
- 在s///中使用分组及后向引用
- eg: sed -r ‘s/i love (\S+) and (\S+)/\1 love \2/’ /tmp/test
-
n : next,读取下一行
-
y/abc/xyz/ : 转换字符,a转成x,b转成y,c转成y,一一对应转换
-
w FILE : write,保存内容
- [line-address]r FILE : read,将文件内容读取到指定行
-
[line-address]q : quit,读取到匹配行之后退出
-
-
模式空间(高级命令)
- N : 将下一行读到模式空间,用\n连接上一行 (注意:是模式空间同一行)
- P : 输出上一行内容
- D : 删除上一行内容,并且继续执行指令 保持空间命令
- h/H : hold,将模式空间内容复制(h),通过\n追加(H)到保持空间
- g/G : get,将保持空间内容复制(g),通过\n追加(G)到模式空间
- x : exchange,将保持空间内容和模式空间内容交
习题1
-
所有以192.168.0.1开头的行都会被替换成它自己加localhost
[root@ ~ 10:42:37]#echo -e '192.168.0.1 xixi\naaa\n192.168.0.1\nbbb'| \ sed -r 's/192.168.0.1/&localhost/g' #-r 支持正则表达式 192.168.0.1localhost xixi aaa 192.168.0.1localhost bbb
-
替换 digit 数字 ,内容为 相同数字
[root@ ~ 10:42:37]#cat test aa digit3 digit44bb 12digitb [root@ ~ 10:42:37]# sed -r 's/digit([0-9])/\1/g' test aa 3 #利用后向引用和s///进行替换 44bb 12digitb
-
love被标记为\1,所有loverable会被替换成lovers,并打印出来
[root@ ~ 10:42:37]#cat test loverabl1 lover loverable [root@ ~ 10:58:46]#sed -r 's/(love)rable/\1rs/g' test loverabl1 #同样使用后向引用 lover lovers
-
使用n或p打印奇数行或偶数行(列出4种方法)
#奇数行 echo -e "a\nb\nc\nd\ne"|sed -n 'P;N' echo -e "a\nb\nc\nd\ne"|sed -n 'p;n' echo -e "a\nb\nc\nd\ne"|sed -n '1~2p' #偶数行 echo -e "a\nb\nc\nd\ne"|sed -n 'n;p' echo -e "a\nb\nc\nd\ne"|sed -n '2~2p'
习题2
-
对于包含test到west之间的行,每行加上字符串’aaa bbb’
[root@ ~/test 04:12:45]#cat test a test hehe west xixi test haha wes . [root@ ~ 11:15:37]#sed -r 's/(test.*west.*$)/\1aaa bbb/g' test a test hehe west xixi aaa bbb #使用后向引用 \1 指代前面括号里的内容 test haha wes .
-
查找包含line1的行到包含line2的行之间的所有aa bbb替换成AA BBB
[root@ ~ 10:42:37]#cat test
aa bbb line1 aa
aa bbb
cc aa bbb
line2
aa bbb
line1
[root@ ~ 11:20:23]#sed '/line1/,/line2/s/aa bbb/AA BBB/g' test
AA BBB line1 aa
AA BBB
cc AA BBB
line2
aa bbb
line1
- 匹配关键字并显示后几行
-
显示第一次匹配到的3到最后一行输出
[root@ ~ 10:42:37]#cat test 1 2 3 4 5 6 [root@ ~ 11:34:17]#echo -e '1\n2\n3\n4\n5\n6' |sed -n '/3/,$p' 3 4 5 6
-
显示第一次匹配到的3到向下两行输出
[root@ ~ 10:42:37]#cat test 1 2 3 4 5 6 [root@ ~ 11:48:19]#sed -n -r '/3/{N;N;p;q}' test 3 #利用两次N将后两行追加到模式空间(同一行,\n分隔离),并打印,默认抑制 4 #注意:第二次匹配到的就不行,所以第一次匹配操作完就退出 5
-
逆序显示文本内容
[root@ ~ 12:09:52]#echo -e '1\n2\n3\n4\n5\n6' |sed -n '1!G;h;$p' 6 #处理行不是第一行,就从保持空间的内容追加到模式空间(形成最新的逆序串) 5 #然后这个串再覆盖保持空间里 4 #当处理完最后一行后,打印保持空间的内容 3 2 1 [root@ ~/test 04:22:22]#sed -n '1h;1!{G;h};$p' test #也可以
-
取出文本中最后一行
[root@ ~ 12:11:17]#echo -e '1\n2\n3\n4\n5\n6' |sed -n '$p' 6 #最后一行,打印
-
删除原有的所有空白行,而后为所有的非空白行后添加一个空白行
[root@ ~ 09:41:39]#echo -e 'a\n\nb\n\nc\nd' a b c d [root@ ~ 09:41:32]#echo -e 'a\n\nb\n\nc\nd'|sed -n -r '/.+/{G;p}' a b c d
-
在原有的每行后方添加一个空白行
[root@ ~ 09:42:27]#echo -e 'a\nb\nc\nd' a b c d [root@ ~ 09:42:06]#echo -e 'a\nb\nc\nd'|sed -n 'G;p' a b c d
-
显示最后一行的行号,一般可用于显示文本的总行数
[root@ ~ 09:50:43]#echo -e 'a\n\n\nb\n\n\nc\nd' a b c d [root@ ~ 10:00:23]#echo -e 'a\n\n\nb\n\n\nc\nd'|sed -n '$=' #打印尾行行号 8
-
显示所有行的行号,但空行不显示行号
[root@ ~ 09:50:43]#echo -e 'a\n\n\nb\n\n\nc\nd' a b c d [root@ ~ 10:02:19]#echo -e 'a\n\n\nb\n\n\nc\nd'|sed -n '/^$/!=' 1 #不是空行就打印行号 4 7 8
习题3
-
删除所有的空行,并在每行后面增加一个空行
[root@ ~/test 04:09:19]#echo -e "\na\n\n\nb\n\nc" a b c [root@ ~/test 04:12:40]#echo -e "\na\n\n\nb\n\nc"|sed -r -n '/^$/!{s/(.*)/\1\n/;p}' #对不是空行的情况尾部增加一个换行符,并且打印,别忘了抑制默认输出 a b c
-
在查找到的行前增加一个空行
[root@ ~/test 04:02:36]#echo -e "a\nb\nc\nd\nd\ne\nf" a b c d d e f [root@ ~/test 04:01:56]#echo -e "a\nb\nc\nd\nd\ne\nf"| \ sed -r 's/(^c.*)/\n\1/' a b c d d e f
-
统计文本的行数
[root@ ~/test 03:58:32]#echo -e "a\nb\nc\nd\nd\ne\nf"|sed -n '$=' 7
-
将没一行的行首的空白字符(空格,制表符)删除
[root@ ~/test 03:55:27]#echo -e " a\n\ta\ta\n a\na\ta" a a a a a a [root@ ~/test 03:55:53]#echo -e " a\n\ta\ta\n a\na\ta"| \ sed -r 's/^( +|\t+)//' a a a a a a
-
将文本中的’aaa’,‘bbb’,‘ccc’都替换为’ttt’
[root@ ~/test 03:49:50]#echo -e "aaa bbb\nbbb\nccc aaa" aaa bbb bbb ccc aaa [root@ ~/test 03:52:06]#echo -e "aaa bbb\nbbb\nccc aaa"| \ sed -r 's/aaa|bbb|ccc/ttt/g' #全局替换,若缺少g则每行最多替换第一个满足的字串 ttt ttt ttt ttt ttt
-
将’yes’替换成’no’,并且只在行中未出现字串’hello’的情况下替换
[root@ ~/test 03:49:09]#echo -e "hello yes sir\nhi yes sir" hello yes sir hi yes sir [root@ ~/test 03:49:39]#echo -e "hello yes sir\nhi yes sir"| \ sed -r '/hello/!s/yes/no/' hello yes sir hi no sir
-
将每行的字符逆序显示
[root@ ~/test 04:12:45]#cat test BEACH HAHA AMAZON ALIBABA HAHA TENCENT PINGLINGLAB HAHA GDUT [root@ ~/test 04:22:22]#sed -n '1h;1!{G;h};$p' test NOZAMA AHAH HCAEB TNECNET AHAH ABABILA TUDG AHAH BALGNILGNIP
-
将数字’1234567’显示为1,234,567
[root@ ~/test 03:46:11]#echo '1234567'|sed 's/1/1,/;s/4/4,/' 1,234,567
-
模拟 tail -1 命令的效果
[root@ ~/test 03:33:01]#cat error.log APPLE XIXI GOOGLE BEACH HAHA AMAZON FACEBOOK XIXI NETEASE ALIBABA HAHA TENCENT ORICLE XIXI SUN PINGLINGLAB HAHA GDUT [root@ ~/test 03:36:40]#sed -n '$!d;$p' error.log #不是尾行就删除,是就打印 PINGLINGLAB HAHA GDUT
-
将如下内容通过sed处理
aaa
bbb
ccc
ddd
eee
fff
变为
aaa bbb
ccc ddd
eee fff
[root@ ~/test 02:59:42]#echo -e 'aaa\nbbb\nccc\nddd\neee\nfff'|sed -n 'N;s/\n/ /;p'
aaa bbb
ccc ddd
eee fff
习题4
-
将error.log中匹配到的内容保存至某文件
[root@ ~/test 03:33:01]#cat error.log APPLE XIXI GOOGLE BEACH HAHA AMAZON FACEBOOK XIXI NETEASE ALIBABA HAHA TENCENT ORICLE XIXI SUN PINGLINGLAB HAHA GDUT [root@ ~/test 03:33:06]#sed '/HAHA/w ./test' error.log #含有HAHA一行就保存到test文件里 [root@ ~/test 03:33:48]#cat ./test BEACH HAHA AMAZON ALIBABA HAHA TENCENT PINGLINGLAB HAHA GDUT
-
将文件中的内容读入到匹配的内容后面
[root@ ~/test 03:03:04]#cat test APPLE XIXI GOOGLE BEACH HAHA AMAZON FACEBOOK XIXI NETEASE ALIBABA HAHA TENCENT ORICLE XIXI SUN PINGLINGLAB HAHA GDUT [root@ ~/test 03:25:39]#cat test|sed -r -n '/HAHA/p;/HAHA/!H;$g;s/^\n//;$p' #以HAHA开头打印,不以HAHA开头追加到扩展空间 BEACH HAHA AMAZON #处理到最后一行,将扩展空间内容覆盖到模式空间 ALIBABA HAHA TENCENT #将模式空间开头的换行符置空 PINGLINGLAB HAHA GDUT #将模式空间打印,打印内容是不以HAHA开头的行 APPLE XIXI GOOGLE FACEBOOK XIXI NETEASE ORICLE XIXI SUN
-
打印匹配到的内容,并显示行号
[root@ ~/test 01:31:53]#cat sedtest |sed -r -n '/ddd$/{=;p}' 7 #行号 7ddd #行号对应内容 14 14aaaddd 21 21aaa ddd
-
删除匹配到的行的下一行
[root@ ~/test 01:20:14]#echo -e '1\n2\n3\n4\n5\n6\n7\n8'|sed -n '/^4/{h;n;g};p' 1 2 3 4 6 7 8
-
删除匹配到的行和下一行
[root@ ~/test 01:23:06]#echo -e '1\n2\n3\n4\n5\n6\n7\n8'|sed '/^4/{N;d}' 1 2 3 6 7 8
-
删除文件每行中的第一个字
[root@ ~/test 01:25:39]#cat sedtest |sed -r 's/^.//g'
-
删除文件每行的第二个字符
[root@ ~/test 01:27:10]#cat sedtest |sed -r 's/(.)(.)(.*)/\1\3/g'
-
删除文件每行的最后一个字符
[root@ ~/test 01:28:11]#cat sedtest |sed -r 's/(.*)./\1/g'
-
删除文件每行的倒数第二个字符
[root@ ~/test 01:28:11]#cat sedtest |sed -r 's/(.*).(.)/\1\2/g'
-
删除每行的最后一个单词
[root@ ~/test 02:47:38]#cat test i have a dream. this is a homework . why don't you join Pinginglab? [root@ ~/test 02:54:30]#cat test|sed -r 's/(.*) ([a-zA-Z]+)(.)/\1\3/g' i have a. this is a . why don't you join?
习题5
-
删除一个文件中的所有的数字
[root@ ~/test 10:35:00]#cat sedtest aaa 11bb22 bb2 33cc44 aaaaaaaaaa [root@ ~/test 10:35:56]#sed -r 's/[0-9]//g' sedtest aaa bb bb cc aaaaaaaaaa
-
将时间格式 yy/mm/dd 的日期换成 yy:mm:dd 的格式( data 命令实现:如2016/08/15变成 2016:08:16)
[root@ ~/test 10:38:46]#cat sedtest a2016/05/31a a 11/01/01a 3/04/30 a [root@ ~/test 10:46:17]#sed -r 's/\b([0-9]+)\/([0-9]{2})\/([0-9]{2})\b/\1:\2:\3/g' sedtest a2016/05/31a a 11/01/01a 3:04:30 a
-
显示奇数行
[root@ ~/test 10:46:37]#cat sedtest a2016/05/31a a 11/01/01a 3/04/30 a [root@ ~/test 11:05:36]#cat sedtest | sed -n '1~2p' a2016/05/31a 3/04/30 a
-
删除模式一到模式二匹配到的行
[root@ ~/test 11:07:52]#echo -e '1\n2\n3\n4\n5\n6' 1 2 3 4 5 6 [root@ ~/test 11:07:45]#echo -e '1\n2\n3\n4\n5\n6' |sed -r '/^2/,/^4/{d}' 1 5 6
-
从指定行开始,每隔2行显示一次
[root@ ~/test 11:07:52]#echo -e '1\n2\n3\n4\n5\n6' 1 2 3 4 5 6 [root@ ~/test 11:22:13]#echo -e '1\n2\n3\n4\n5\n6' |sed -n '2~3p' 2 5
-
删除文中的最后两行
[root@ ~/test 11:38:53]#echo -e '1\n2\n3\n4\n5\n6' 1 2 3 4 5 6 [root@ ~/test 05:14:34]#echo -e "1\n2\n3\n4\n5" | \ sed -r -n 'H;$g;$s/\n(.*)\n(.*)\n(.*)/\1/;$p' 1 2 3
-
删除文中的空行
[root@ ~/test 11:44:17]#echo -e '1\n\n2\n\n3\n4\n\n5\n6' 1 2 3 4 5 6 [root@ ~/test 11:44:22]#echo -e '1\n\n2\n\n3\n4\n\n5\n6'|sed '/^$/d' 1 2 3 4 5 6
-
每隔5行增加一个空行
[root@ ~/test 11:58:39]#echo -e '1\n2\n3\n4\n5\n6\n7\n8' 1 2 3 4 5 6 7 8 [root@ ~/test 12:01:17]#echo -e '1\n2\n3\n4\n5\n6\n7\n8'|sed -r -n '0~5G;p' #从开始起每逢五行从扩展空间追加一个换行符到模式空间,并打印模式空间内容 1 2 3 4 5 6 7 8
-
不显示指定字符开始的行
[root@ ~/test 12:48:09]#echo -e '1\n2\n3\n4\n5\n6\n7\n8'|sed -r -n '/^4/d;p' #不显示以4开头的行 1 2 3 5 6 7 8
-
查找文件中1到20行之间,同事将’aaa’替换为’AAA’,‘ddd’替换成’DDD’
[root@ ~/test 12:52:54]#sed -r '1,20y/aaa/AAA/;1,20y/ddd/DDD/' sedtest 1 2 3 4 5DDD AAA 6 7DDD 8 9 10AAA 11 12 13 14AAADDD 15 16 17 18 19 20 21aaa ddd #可以看到哦第21行没有被替换