sed命令

英文全称 Stream EDitor

原理

SED遵循简单的工作流:读取,执行和显示,下图描述了该工作流

  • 读取: SED从输入流(文件,管道或者标准输入)中读取一行并且存储到 叫做 模式空间(pattern buffer) 的内部缓冲区
  • 执行: 默认情况下,所有的SED命令都在模式空间中顺序的执行,除非指定了行的地址,否则SED命令将会在所有的行上依次执行
  • 显示: 发送修改后的内容到输出流。在发送数据之后,模式空间将会被清空。
  • 在文件所有的内容都被处理完成之前,上述过程将会重复执行

需要注意的几点

  • 模式空间 (pattern buffer) 是一块活跃的缓冲区,在sed编辑器执行命令时它会保存待检查的文本
  • 默认情况下,所有的SED命令都是在模式空间中执行,因此输入文件并不会发生改变
  • 还有另外一个缓冲区叫做 保持空间 (hold buffer),在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。在每一个循环结束的时候,SED将会移除模式空间中的内容,但是该缓冲区中的内容在所有的循环过程中是持久存储的。SED命令无法直接在该缓冲区中执行,因此SED允许数据在 保持空间 和 模式空间之间切换
  • 初始情况下,保持空间 和 模式空间 这两个缓冲区都是空的
  • 如果没有提供输入文件的话,SED将会从标准输入接收请求
  • 如果没有提供地址范围的话,默认情况下SED将会对所有的行进行操作

语法:

命令格式: sed  [option]   'sed command'    filename

脚本格式:sed   [option]   -f    'sed script'     filename

选项:

        -n∶只显示匹配行
        -e∶直接在命令行模式上进行sed动作编辑,此为默认选项
        -f∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;
        -r∶支持扩展正则
        -i∶直接修改文件内容

sed编辑命令:
        a   ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
        c   ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
        d   ∶删除
         i   ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
         p  ∶打印
         s  ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

     

举例:

   1、行寻址

打印第2行,sed默认打印文件中所有行
[root@localhost] ~$ sed '2p' data this is the header line this is the first data line this is the first data line this is the second data line this is the last line

只打印第2行
[root@localhost]
~$ sed -n '2p' data
打印1-3行 [root@localhost]
~$ sed -n '1,3p' data
打印第2行开始加下面4行,即2,3,4,5,6,行
sed -n '2,+4 p' books.txt

打印第1行开始的每2行。例如,1~2匹配行号1,3,5,7等,让我们只输出文件中的奇数行
sed -n '1~2 p' books.txt


匹配second行
[root@localhost]
~$ sed -n '/second/p' data this is the second data line

打印first行到第4行
[root@localhost]
~$ sed -n '/first/,4p' data this is the first data line this is the second data line this is the last line
打印data行到last行 [root@localhost] ~$ sed -n '/data/,/last/p' data this is the first data line this is the second data line this is the last line
过滤#开头的行
[root@localhost] ~$ sed -n '/^#/!p'  /etc/rc.d/rc.local 

touch /var/lock/subsys/local
过滤#开头的行,将结果传入{},再过滤空行
[root@localhost] ~$ sed -n '/^#/!{/^$/!p}'  /etc/rc.d/rc.local 
touch /var/lock/subsys/local
对单个文件实现不同的操作,每个操作用-e参数
[root@localhost] ~$ sed -e '/^#/d' -e '/^$/d'  /etc/rc.d/rc.local 
touch /var/lock/subsys/local

2、a 添加 (i 插入 同理)

在第四行之后添加hello world
sed
'4 a hello world' books.txt

 

3、替换

sed 's/原字符串/替换字符串/'         只替换每行匹配到的第一个字符串

sed 's/原字符串/替换字符串/2'     只替换每行匹配到的第二个字符串

sed 's/原字符串/替换字符串/g'     替换所有字符串

 

在执行替换操作的时候,如果要替换的内容中包含/,这个时候怎么办?很简单,添加转义操作符。

$ echo "/bin/sed" | sed 's/\/bin\/sed/\/home\/mylxsw\/src\/sed\/sed-4.2.2\/sed/'
/home/mylxsw/src/sed/sed-4.2.2/sed

上面的命令中,我们使用\对/进行了转义,不过表达式已经看起来非常难看了,在SED中还可以使用|,@,^,!作为命令的分隔符,所以,下面的几个命令和上面的是等价的

echo "/bin/sed" | sed 's|/bin/sed|/mylxsw/mylxsw/src/sed/sed-4.2.2/sed|'
echo "/bin/sed" | sed 's@/bin/sed@/home/mylxsw/src/sed/sed-4.2.2/sed@'
echo "/bin/sed" | sed 's^/bin/sed^/home/mylxsw/src/sed/sed-4.2.2/sed^'
echo "/bin/sed" | sed 's!/bin/sed!/home/mylxsw/src/sed/sed-4.2.2/sed!'

 

 

 

 

 c 行替换

把第4行替换为hello world
sed '4 c hello world' books.txt 

把第4-6行替换为hello world
sed '4, 6 c hello world' books.txt 

 

 

4、y  转换(Translate)是唯一可以处理单个字符的命令

转换命令会对inchars和outchars值进行一对一的映射。这个映射过程会一直持续到处理完指定字符。如果inchars和outchars的长度不同,则产生错误。


$ echo "1 5 15 20" | sed 'y/151520/IVXVXX/'
I V IV XX

[root@localhost] ~$ echo "1 5 15 201" | sed 'y/151520/IVXVXX/'
I V IV XXI

[root@localhost] ~$ echo "1 5 15 201" | sed 'y/1515201/IVXVXX/'
sed: -e expression #1, char 17: strings for `y' command are different lengths

[root@localhost] ~$ echo "11 5 15 201" | sed 'y/151520/IVXVXX/'
II V IV XXI

[root@localhost] ~$ echo "11 5 15 203" | sed 'y/151520/IVXVXX/'
II V IV XX3

 

 

5、w 将匹配到的内容写入文件 ,注意w和文件名之间只能有一个空格

将books.txt的内容写入books.bak,相当于cp
sed -n 'w books.bak' books.txt

把偶数行写入到junk.txt
sed -n '2~2 w junk.txt' books.txt

分别匹配写入
sed -n -e '/Martin/ w Martin.txt' -e '/Paulo/ w Paulo.txt' books.txt 

在test文件中匹配IPADDR所在的行,然后用ip替换IPADDR,然后保存到ip.txt
[root@jie1 ~]# sed -i 's/IPADDR/ip/ w ip.txt' test

 

5、r  文件读取命令,r命令和文件名之间必须只有一个空格。

打开junk.txt文件,将其内容插入到books.txt文件的第三行之后
$ echo "This is junk text." > junk.txt 
$ sed '3 r junk.txt' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
This is junk text. 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

r命令也支持地址范围,例如3, 5 r junk.txt会在第三行,第四行,第五行后面分别插入junk.txt的内容

 

 

 

6、 l:输出隐藏字符命令 ,你能通过直接观察区分出单词是通过空格还是tab进行分隔的吗?显然是不能的,但是SED可以为你做到这点。使用l命令(英文字母L的小写)可以显示文本中的隐藏字符(例如\t或者$字符)。

先将books.txt中的空格替换为tab
$ sed 's/ /\t/g' books.txt > junk.txt

显示隐藏字符
$ sed -n 'l' junk.txt
1)\tStorm\tof\tSwords,\tGeorge\tR.\tR.\tMartin,\t1216\t$
2)\tThe\tTwo\tTowers,\tJ.\tR.\tR.\tTolkien,\t352\t$
3)\tThe\tAlchemist,\tPaulo\tCoelho,\t197\t$
4)\tThe\tFellowship\tof\tthe\tRing,\tJ.\tR.\tR.\tTolkien,\t432\t$
5)\tThe\tPilgrimage,\tPaulo\tCoelho,\t288\t$
6)\tA\tGame\tof\tThrones,\tGeorge\tR.\tR.\tMartin,\t864$

另外加上数字,可以按照每行25个字符进行换行
$ sed -n 'l 25' books.txt

 

8、q 退出命令

打印到第3行退出 
$ sed '3 q' books.txt 1) A Storm of Swords, George R. R. Martin, 1216 2) The Two Towers, J. R. R. Tolkien, 352 3) The Alchemist, Paulo Coelho, 197

 

 9、e 执行外部命令

 

下面的命令会在第三行之前执行date命令

$ sed '3 e date' books.txt
1) Storm of Swords, George R. R. Martin, 1216 2) The Two Towers, J. R. R. Tolkien, 352 2016年11月29日 星期二 22时46分14秒 CST 3) The Alchemist, Paulo Coelho, 197 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 5) The Pilgrimage, Paulo Coelho, 288 6) A Game of Thrones, George R. R. Martin, 864 如果你仔细观察e命令的语法,你会发现其实它的command参数是可选的。在没有提供外部命令的时候,SED会将模式空间中的内容作为要执行的命令。 $ echo -e "date\ncal\nuname" > commands.txt $ cat commands.txt date cal uname $ sed 'e' commands.txt 2016年11月29日 星期二 22时50分30秒 CST 十一月 2016 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Darwin

 

10、提取子字符串(重点)


现在有如下一串字符串:
"asdfkjasldjkf"shiner"df

需求:
需要提取出shiner子字符串。

命令如下:
[root@localhost /]$ echo "asdfkjasldjkf\"shiner\"df" | sed 's/\(.*\)"\(.*\)"\(.*\)/\2/g'
shiner

命令解释
s: 表示替换命令
\(.*\)" : 表示第一个引号前的内容
"\(.*\)":表示两引号之间的内容
)"\(.*\):表示引号后的内容
\2: 表示第二对括号里面的内容

括号里的表达式匹配的内容,可以用\1,\2等进行引用,第n个括号对内的内容,就用\n引用。

这个命令的意思是:
用\2代表的第二个括号的内容(shiner)去替换整个字符串,这样就得到了我们所需要的子字符串了。

 

特殊字符   = 和 & 

=    输出行号

为每一行输出行号
sed '=' books2.txt

为1-4行输出行号
sed '1, 4 =' books2.txt

最后一行输出行号,可以用于输出文件总共有多少行
sed -n '$ =' books2.txt

 

 

sed常见面试题

##1)、处理以下文件内容,将域名取出并进行计数排序,如处理:  
http://www.baidu.com/index.<a target="_blank" href="http://www.2cto.com/kf/qianduan/css/" class="keylink" style="border:none; padding:0px; margin:0px; color:rgb(51,51,51); text-decoration:none; font-size:14px">html</a>  
http://www.baidu.com/1.html  
http://post.baidu.com/index.html  
http://mp3.baidu.com/index.html  
http://www.baidu.com/3.html  
http://post.baidu.com/2.html  
得到如下结果:  
域名的出现的次数 域名  
3 www.baidu.com  
2 post.baidu.com  
1 mp3.baidu.com  ,
[root@localhost shell]# cat file | sed -e ' s/http:\/\///' -e ' s/\/.*//' | sort | uniq -c | sort -rn    #把http://用空格代替,把/后面跟任意字符用空格代替,排序,去重,再反向排序
3 www.baidu.com  
2 post.baidu.com  
1 mp3.baidu.com  
[root@codfei4 shell]# awk -F/ '{print $3}' file |sort -r|uniq -c|awk '{print $1"\t",$2}'  
3 www.baidu.com  
2 post.baidu.com  
1 mp3.baidu.com  

 

 参考

http://blog.jobbole.com/109088/

http://blog.chinaunix.net/uid-12453618-id-2935273.html

https://www.cnblogs.com/ctaixw/p/5860221.html

 



 

posted @ 2017-03-01 21:07  fanren224  阅读(198)  评论(0编辑  收藏  举报