初识sed(上)

来源:岁月联盟 编辑:exp 时间:2012-02-16
寒假在家把《Sed and Awk 101 Hacks》一书翻了下,再看了其他一些零零碎碎的资料,大概算是把sed和awk给入门了(其实sed和awk也易学哈)。趁着这几天刚开学课少把知识点整理一遍,遂有下文。篇幅较长,我分为上下两部分,免得读者看着累哈。由于是学习笔记,可能理解不深甚至有误,再加上有些地方“搬”的不好(看的英文资料但我英文挺锉额,所以有不少地方我保留为英文),错误之处望指正。
 
符号约定:
[] 可选  <>必选
 
sed是stream editor的简称,是一种在线编辑器,一次处理一行文本。一般而言,sed的执行流程分为四个阶段:
 
 /
 
进行文本处理时,sed会从输入流(可以是文件或者管道)读取(Read)一行文本并存储在pattern space中。sed有两个内建的暂存区:pattern space和hold space。pattern space存储着从输入流读入的文本。hold space是一个“自由”空间,可以在其中存放临时数据。(attention:两个暂存区的数据是可以通过用户改变的哦!具体的后边会提及)读取一行到pattern space后,sed便会根据给定的命令处理pattern space中的数据。处理完以后,sed默认把pattern space的数据送往屏幕,即打印啦!紧接着sed便按照同样的流程处理下一行,一直重复下去直到输入流结束。
 
sed基本语法格式如下:
 
sed [options] <sed-commands> [input-file]
当没有指定输入时,sed默认处理标准输入流。
注意:由前面的sed执行流程可知,sed并不会改变输入文件,除非使用重定向存储输出或相关的sed命令。
 
sed常用选项介绍
-n, --quiet, --silent
 
默认情况下sed会在流程的最后打印pattern space中的内容,如果加上上面任一选项,则可取消该默认设置。
 
 
-e script, --expression=script
 
指定sed命令,一般用于有多个command的情况,如下:
 
sed -n -e 's/cassvin/Leon/' -e 'p' example.txt
表示把example.txt中的cassvin(假如有的话)替换为Leon并打印出来(s/pattern/dest/是匹配命令,p是打印命令,后续会介绍)
 
 
-f script-file
 
除了可以使用-e指定多个sed commands,还可以将commands写入到脚本文件中,然后通过-f script-file来指定。如前面的例子中,commands放入脚本文件中:
 
#!/bin/sed -fs/cassvin/Leon/p复制代码
注意,启动sed以-f选项引导脚本文件,所以-f是不能被略去的且应放在众多选项最后,如:要同时关闭sed的默认打印选项,则应如此书写:#!/bin/sed -nf
如果书写为:#!/bin/sed -fn,则会报错:Can not find file n:***********
 
 
-i[suffix], --in-place[=suffix]
 
sed是不会改写输入文件内容,除非使用上面的选项。suffix即备份后缀名。举例:
 
sed -n -ibak 's/cassvin/Leon/' example.txt
sed将改写example.txt,example.txt中的cassvin将会改写为Leon。不过放心,sed已经为我们做好了备份,备份文件名为example.txtbak。
 
 
-c, --copy
 
该选项需配合-i一起使用。使用-c -i[suffix]后输入文件不会被改写,sed会创建临时文件(文件名为输入文件名+后缀名)保存修改后的内容。如:
 
sed -ibak -c 's/cassvin/Leon/' example.txt
example.txt不会被改写,sed会创建example.txtbak保存修改后的内容。
 
 
sed常用命令介绍
介绍完几个常用的sed选项,下面我们配合sed选项介绍sed命令。为此创建一份样例employee.txt:
 
101, John Doe, CEO102, Jason Smith, IT Manager103, Raj Reddy, Sysadmin104, Anand Ram, Developer105, Jane Miller, Sales Manager复制代码
前面已经说过,在sed中命令可以有多个,可以通过-e指定也可以将命令写入到脚本文件中。其实,当sed命令有多个时,还可以通过";"来分隔。如:
 
sed -n 's/John/Jason/; p' employee.txt
上面的命令把employee.txt中的John替换为Jason并打印出来。
除此以外,还可以用{}将sed命令括起,效果是一样的:
 
sed -n '{ s/John/Jason/; p }' employee.txt
 
p command
 
打印当前pattern space中的内容并清空,经常配合-n选项使用。如果没有指定打印的行,p默认打印输入流中的所有行。
 
 
在sed中,我们可以直接给出数字来指定行(也可以指定范围)。或者通过模式匹配指定对应的行。不管是数字,模式还是其他,能够指定对应的行或者行范围在sed我们称之为Address。
(原谅我把sed命令停下,Address确实很重要。)
如前所言,Address有多种形式,数字,模式匹配,等等。下面通过实例介绍。
通过数字指定:
 
sed -n 'n p' employee.txt              打印第n行sed -n 'n, m p' employee.txt             打印n到m行(包括第n行)sed -n 'n, $ p' employee.txt             打印第n行到行尾,$表示行尾sed -n 'n, +m p' employee.txt            打印n到m行,+m表示以n为基数打印m+n行sed -n 'n~m p' employee.txt             1~2表示1,3,5,etc, 2~2表示2,4,6,etc复制代码
以此类推。
通过模式匹配指定:
 
sed -n '/John/ p' employee.txt            打印"101, John Doe, CEO"一行sed -n '/Raj/, /Jane/ p' employee.txt           得到输出结果如下:103,Raj Reddy,Sysadmin104,Anand Ram,Developer105,Jane Miller,Sales Managersed -n '/Anand Ram/, $ p' employee.txt得到输出结果如下:104,Anand Ram,Developer105,Jane Miller,Sales Manager复制代码
模式匹配和数字配合使用:
 
sed -n '/John/, 2 p' employee.txt101, John Doe, CEO102, Jason Smith, IT Managersed -n '/John/, +2 p' employee.txt101, John Doe, CEO102, Jason Smith, IT Manager103,Raj Reddy,Sysadmin复制代码
注意没有sed -n '/John/~2 p' employee.txt这种形式。
 
 
d command
 
删除当前pattern space中的内容,可以配合Address使用。如果没有指定Address,那么sed会匹配所有的行。即d命令将会删除所有的行(当然不影响到输入文件)
 
sed '2 d' employee.txt               删除第二行sed '2, $ d' employee.txt             从第二行删除直到行尾etc...其他类同,可以参考前面关于Address的介绍复制代码
 
w command
 
语法格式:sed 'w output-file' input-file
将当前pattern space的内容写入到指定文件中。注意,如果不使用-n,sed还会将pattern space的内容打印到屏幕上。
sed -n 'w output.txt' employee.txt 相当于复制employee.txt到output.txt
类似的,w可以配合Address使用,具体不表
w命令用的情况可能不是很多,大多数情况下人们习惯于用重定向将修改后的内容保存到文件中,如下两个命令是等价的:
 
sed -n '2, 4 w output.txt' employee.txtsed -n '2, 4 p' employee.txt > output.txt复制代码
 
r command
 
在指定的位置读入文件并打印。
 
sed '& r tmp.txt' employee.txt
将在employee.txt后面添加tmp.txt的内容
 
 
a command
 
语法格式:sed '<address> a line-content' [input-file]
在指定的位置附加行。注意是append哦,sed读到指定的位置便会把待插的新行附加到当前pattern space的后边。举例:
 
sed -n -e '2 a 202, Leon Hui, Student' -e '2 p' employee.txt102, Jason Smith, IT Manager202, Leon Hui, Student复制代码
其他Address类同
 
 
i command
 
语法格式:sed '<address> i line-content' [input-file]
类似a command。不过a是append,而i是insert,即在指定位置前插入。
 
sed -n -e '2 i 201, Leon Hui, Student' -e '2 p' employee.txt201, Leon Hui, Student102, Jason Smith, IT Manager复制代码
其他Address类同
 
 
c command
 
语法格式:sed '<address> c line-content' [input-file]
c即change。改变指定位置的行。
 
sed '2 c 202, Leon Hui, Student' employee.txt101, John Doe, CEO202, Leon Hui, Student……复制代码
其他Address类同
 
a, i, c还可以配合使用,见实例:
 
sed '/Jason/ {a 204,Jack Johnson,Engineer/i 202,Mark Smith,Sales Engineer/c 203,Joe Mason,Sysadmin/}' employee.txt101,John Doe,CEO202,Mark Smith,Sales Engineer203,Joe Mason,Sysadmin204,Jack Johnson,Engineer103,Raj Reddy,Sysadmin 复制代码
 
I command
 
打印隐藏字符诸如/t, /n之类。例如,name school加I打印为name/tschool
 
 
= command
打印行号。见实例:
 
sed -n '1, 3 {=;p}' employee.txt1101, John Doe, CEO2102, Jason Smith, IT Manager3103, Raj Reddy, Sysadmin复制代码
其他Address类似
看到上面的命令读者可能会有些许疑惑,为何是"1, 3{=; p}",可不可以是"1, 3 =; p"呢?这是不可以的,后者会把第四第五行也给打印出来。在"1, 3{=; p}"中,当sed读到第四行时,由于4不在1,3的范围内,所以{}内的=; p命令行不会执行,即第四行不会被添加行号也不会打印出来。但是命令"1, 3 =; p"中就不同了。4不满足1,3范围自然不会被执行=命令。但由于此时p不是像前一个命令被1,3这个条件所束缚,它会打印所有的行。所以之后的4, 5行自然也就打印出来了,简言之,第二条命令相当于:1, 3 {=}; p
 
 
y command
 
字符转换。语法格式:sed 'y/orgin_chars/dest_chars/' input-file
orgin_chars和dest_chars必须一样长,不然会报错。
sed 'y/a/b' employee.txt 将employee.txt中的a替换为b
sed 'y/abcde/ABCDE' employee.txt 大小写转换
 
 
q command
 
q command即quit。使用q命令时,sed打印当前pattern space中的内容后便终止退出程序。见实例:
 
sed '2 q' employee.txt101,John Doe,CEO102,Jason Smith,IT Manager复制代码
同样的,q可以配合Address使用。
 
 
 
(上完,待续)
 
作者 cassvin