初识sed(上)

  寒假在家把《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 -f
s/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, CEO
102, Jason Smith, IT Manager
103, Raj Reddy, Sysadmin
104, Anand Ram, Developer
105, 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,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

sed -n '/Anand Ram/, $ p' employee.txt
得到输出结果如下:
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

模式匹配和数字配合使用:

sed -n '/John/, 2 p' employee.txt
101, John Doe, CEO
102, Jason Smith, IT Manager

sed -n '/John/, +2 p' employee.txt
101, John Doe, CEO
102, Jason Smith, IT Manager
103,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.txt
sed -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.txt
102, Jason Smith, IT Manager
202, 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.txt
201, Leon Hui, Student
102, Jason Smith, IT Manager

其他Address类同


c command

语法格式: sed '<address> c line-content' [input-file]
c即change。改变指定位置的行。

sed '2 c 202, Leon Hui, Student' employee.txt
101, John Doe, CEO
202, 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.txt
101,John Doe,CEO
202,Mark Smith,Sales Engineer
203,Joe Mason,Sysadmin
204,Jack Johnson,Engineer
103,Raj Reddy,Sysadmin 


I command

打印隐藏字符诸如\t, \n之类。例如,name school加I打印为name\tschool


= command

打印行号。见实例:

sed -n '1, 3 {=;p}' employee.txt
1
101, John Doe, CEO
2
102, Jason Smith, IT Manager
3
103, 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.txt
101,John Doe,CEO
102,Jason Smith,IT Manager

同样的,q可以配合Address使用。

 

上完,待续

posted @ 2012-02-15 12:20  cassvin  阅读(...)  评论(...编辑  收藏