Stream Editor主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。以下介绍的是Gnu版本的Sed。
定址选定希望编辑的行的范围 | |
$ sed -n p file | $ sed -n '2,$p' file |
$ sed ‘/music/=’ 打印行号 | $ sed -n '3,+1p' file |
$ sed -n ‘/.*ing/!p’ install.log | 把不含‘样式’的数据行删除 |
$ sed -n /lang/!p file | $ sed -n '5,/^test/p' file |
$ sed '/his/,/her/s/$/*******/' file | 末尾用*******替换 |
$ sed 's/erors/errors/' file one errors, two erors. | $ sed 's/erors/errors/g' file one errors, two errors. |
一.sed [option] [action]
1.[option]:-nerfi
-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的数据一般都会被列出到屏幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。 |
-e :直接在指令列模式上进行 sed 的动作编辑; |
-f :直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作; |
-r :sed 的动作支持的是延伸型正则表达式的语法。(预设是基础正则表达式语法) |
-i :直接修改读取的档案内容,而不是由屏幕输出。 |
2.[action]:[n1[,n2]] function
①n1, n2 :不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作是需要在 10 到 20 行之间进行的,则『 10,20[动作行为] 』
②function
a\ :在当前行后面加入一行文本。 b lable :分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。 c\ :用新的文本改变本行的文本。 d :从模板块(Pattern space)位置删除行。 D:删除模板块的第一行。 i\ :在当前行上面插入文本。 h :拷贝模板块的内容到内存中的缓冲区。 H :追加模板块的内容到内存中的缓冲区 g :获得内存缓冲区的内容,并替代当前模板块中的文本。 G :获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l :列表不能打印字符的清单。 n :读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。 N :追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。 p :打印模板块的行。 P :打印模板块的第一行。 q :退出Sed。 r file :从file中读行。 t label :if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。 T label :错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。 w file :写并追加模板块到file末尾。 W file :写并追加模板块的第一行到file末尾。 ! :表示后面的命令对所有没有被选定的行发生作用。 s/re/string :用string替换正则表达式re。 = :打印当前行号码。 # :把注释扩展到下一个换行符以前。 |
{} 在定位行执行的命令组 |
以下的是替换标记 g:表示行内全面替换。 p:表示打印行。 w:表示把行写入一个文件。 x:表示互换模板块中的文本和缓冲区中的文本。 y:表示把一个字符翻译为另外的字符(但是不用于正则表达式) |
三.经典范例
1.列出/etc/passwd的内容,并且打印行号,同时,请将第2~5行删除!,在第二行后面加入两行字,例如『Drink tea or .....』『drink beer?』
# nl /etc/passwd | sed '2aDrink tea or ......\ > drink beer ?' 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin Drink tea or ...... drink beer ? 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin |
#每一行之间都必须要以反斜线 \ 来进行新行的增加 #在 a 后面加上的字符串就已将出现在第二行后面啰!那如果是要在第二行前呢? # nl /etc/passwd | sed '2i drink tea' 就对啦! |
2.我想将第2-5行的内容取代成为『No 2-5 number』呢?
# nl /etc/passwd | sed '2,5cNo 2-5 number' 1 root:x:0:0:root:/root:/bin/bash No 2-5 number 6 sync:x:5:0:sync:/sbin:/bin/sync |
3.仅列出第 5-7行
# nl /etc/passwd | sed -n '5,7p' |
# sed '5,7p' (没加-n5-7行会重复输出) |
4.我们可以使用 ifconfig来列出 IP,若仅要 eth0的 IP时?
# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:51:FD:52:9A:CA inet addr:192.168.1.12 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::250:fcff:fe22:9acb/64 Scope:Link .....(以下省略)..... |
# 其实,我们要的只是那个 inet addr:..那一行而已,所以利用 grep 与sed 来捉 # ifconfig eth0 | grep 'inet ' | sed 's/^.*addr://g' | sed 's/Bcast.*$//g' 192.168.0.189 |
# 您可以将每个管线 (|) 的过程都分开来执行,就会晓得原因啰! |
5.将/etc/man.config中,有MAN的设定取出来,但不要说明内容
# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g' | sed '/^$/d' |
# 每一行当中,若有 # 表示该行为批注 |
6.利用 sed直接在 ~/.bashrc最后一行加入『# This is a test』
# sed -i '$a # This is a test' ~/.bashrc |
# -i 参数可以让你的 sed 直接去修改后面接的档案内容喔!而不是由屏幕输出。 # 至于那个 $a 则代表最后一行才新增的意思 |
7.sed脚本文件(以#开头的行为注释行)
行尾不能有空白或文本,一行中有多个命令用分号分隔。
8.按顺序执行{}括号里的命令
9.sed –r使用扩展正则
10.行号:=命令
sed -n '$=' 计算行数 (模拟 "wc -l") |
# df -h|sed =|sed 'N;s/\n/ /' 1 Filesystem Size Used Avail Use% Mounted on 2 /dev/mapper/vol0-root 3 7.8G 2.6G 4.9G 35% / |
# df -h|sed = | sed 'N;s/\n/\t/' 1 Filesystem Size Used Avail Use% Mounted on 2 /dev/mapper/vol0-root 3 7.8G 2.6G 4.9G 35% / |
11.下一个:n命令
sed 'n;d' 删除所有偶数行 |
sed -n '/regexp/{n;p;}' 显示匹配行的下一行 |
sed 'n;n;n;n;n;n;n;d;' 其他sed, # 删除8的倍数行 sed -n '3,${p;n;n;n;n;n;n;}' 从第3行开始,每7行显示一次 sed '/test/{ n; s/aa/bb/; }' file 移到匹配行的下一行替换并替换 |
[address1 ,[address2]]N最多两个地址 添加一笔资料在pattern space 内 sed -e 'N' -e 's/\n/ /' input.dat 每两行连成一行,类似paste The UNIX Operating System 原input.dat 的内容如下: The UNIX Operating System |
sed '/./=' file | sed '/./N; s/\n/ /' 对所有行编号,但只显示非空行的行号 |
12.退出:q命令(最多配合一个地址参数)
sed 10q 显示文件中的前10行 (模拟“head”) |
sed q 显示文件中的第一行 (模拟“head -1”) |
sed -e '/zcs/q' 遇到"zcs"就中止sed |
13.标记:b:label命令
与函数参数b 可在sedscript 内建立类似BASIC 语言中GOTO 指令的功能。其中, 函数参数: 建立标记;函数参数b 将下一个执行的指令branch 到标记处执行。函数参数: 与b , 在script file 内配合的情况如下 编辑指令m1 :记号 编辑指令m2 [address1,[address2]]b [记号] 其中, 当sed执行至指令[address1,[address2]]b [记号] 时, 如pattern space 内的数据符合地址参数, 则sed将下一个执行的位置branch 至由:记号设定的标记处, 也就是再由"编辑指令m2" ... 执行。另外, 如果指令中参数b 后没有记号, 则sed将下一个执行的指令branch 到script file 的最后, 利用此可使sedscript 内有类似C 语言中的case statement 结构。 题目: 将input.dat 文件内数据行的开头字母重复印40 次。假设input.dat 檔的内容如下: A B C 说明: 用指令b p1 与:p1 构成执行增加字母的循环(loop) , 同时在字母出现40 个时, 也用指令b 来跳出循环。下面就以文件内第一行数据"A" 为例, 描述它如何连续多添加39 个"A" 在同一行: 用指令s/A/AA/将"A" 替换成"AA"。 用指令b p1 与:p1 构成循环(loop) , 它目的使上述动作被反复的执行。每执行一次循环, 则数据行上的"A" 就多出一个。例如, 第一次循环数据行变成"AA" , 第二次循环资料行变成"AAA" ...。 用指令[ABC]\{40\}/b来作为停止循环的条件。当数据行有连续40 个A 出现时, 参数b 将执行的指令跳到最后, 停止对此行的编辑。 同样, 对其他数据行也如同上述的方式执行。 sed 命令列如下: sed -e '{ :p1 /A/s/A/AA/ /B/s/B/BB/ /C/s/C/CC/ /[ABC]\{40\}/b b p1 }' input.dat |
14.标记:t:label命令
执行t 的branch前, 会先去测试其前的替换指令有没有执行替换成功。 在script file 内的情况如下: 编辑指令m1 :记号 编辑指令m2 s/.../.../ [address1,[address2]]t [记号] 编辑指令m3 其中, 与参数b不同处在于, 执行参数t branch时, 会先检查其前一个替换指令成功与否。如成功,则执行branch ; 不成功,则不branch , 而继续执行下一个编辑指令, 题目: 将input.dat文件中资料A1 替换成C1.C1替换成B1.B1 替换成A1。 input.dat 檔的内容如下: 代号 B1 A1 B1 C1 A1 C1 说明: input.dat 文件中全部数据行只需要执行一次替换动作,但为避免数据被替换多次, 所以利用函数参数t在sedscript 内形成一类似C语言中case statement 结构,使每行数据替换一次后能立即用函数参数t 跳离替换编辑。 sed 命令列: sed -e '{ s/A1/C1/ t s/C1/B1/ t s/B1/A1/ t }' input.dat |