Sed
Sed(Stream EDitor)为 UNIX 系统上提供将编辑工作自动化的编辑器,使用者无需直接编辑数据。使用者可利用 sed 所提供 20 多种不同的函数参数,组合(批注 [1])它们完成不同的编辑动作。此外,由于 sed 都以行为单位编辑文件,故其亦是行编辑器(line editor)。它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed 主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
目录 |
1 命令形式
调用sed命令有两种形式:
sed [options] 'command' file(s) sed [options] -f scriptfile file(s)
sed 编辑指令的格式如下 :
[address1[,address2]]function[argument]
其中,位址 address1 、address2 为行数或 regular expression 字串,表示所执行编辑的资料行,函数参数 function[argument] 为 sed 的内定函数,表示执行的编辑动作。
两个撇号 (' ') 之间的全部内容都被解释为 sed 命令。直到您输入了第二个撇号,读入这些命令的 shell 程序才会认为您完成了输入。这意味着可以在多行上输入命令—同时 Linux 将提示符从 PS1 变为一个延续提示符(通常为 ">")—直到输入了第二个撇号。一旦输入了第二个撇号,并且按下了 Enter 键,则处理就进行并产生相同的结果,如下所示:
$ echo The tiger cubs will meet on Tuesday after school | sed ' > s/tiger/wolf/ > s/after/before/' The wolf cubs will meet on Tuesday before school $
2 多条编辑指令
如果没有指定 -e 选项或者 -f 选项,那么, Sed 把遇到的第一个非选项参数当作命令来执行。比如以下命令直接执行替换操作:
sed 's/old/new/' test.txt
如果要对一行执行多个命令,有以下几种方法:
- 使用 -e 选项,每个 -e 可以后跟一个命令,替换test.txt中的 one 为 first,two 为 second:
sed -e 's/one/first/' -e 's/two/second/' test.txt
- 另一个比较简便的方法是使用分号(;):
sed 's/one/first/'; -e 's/two/second/' test.txt
- 第三种方法是使用脚本文件,将所要执行的操作记录到文件中,并用 -f 选项调用,这个选项可以实现很复杂的操作:
sed -f sedlist test.txt
3 全局开关
默认 sed 只对找到的第一个匹配执行命令,如果要对所有匹配进行命令操作就要使用全局开关 g,例如:
$ echo The tiger cubs will meet this Tuesday at the same time as the meeting last Tuesday | sed 's/Tuesday/Thursday/g' The tiger cubs will meet this Thursday at the same time as the meeting last Thursday $
4 输出
sed 的执行过程是读取一行然后处理后输出,它并不修改源文件,您必须将输出保存至另一个文件,以实现永久保存。
以下命令将修改后的输出保存至一个新的文件:
$ sed ' > /two/ s/1/2/ > /three/ s/1/3/' sample_one > sample_two
5 显示
sed 默认将来自源文件的每一行显示到屏幕上(或重定向到一个文件中),而无论该行是否受到编辑操作的影响,"-n" 参数覆盖了这一操作。"-n" 覆盖了所有的显示,并且不显示任何一行,而无论它们是否被编辑操作修改。例如:
sed -n '/two/ s/1/2/' sample_one
以上示例在屏幕上不显示任何东西。 要显示只被修改过的行,则使用 p 参数即可:
sed -n '/two/ s/1/2/p' sample_one
利用它的另一种方法是只显示一定数量的行。例如,只显示 2-6 行,同时不做其它的编辑修改:
sed -n '2,6p' sample_one
其它所有的行被忽略,只有 2-6 行作为输出显示。这是一项出色的功能,其它任何工具都不能容易地实现。Head 将显示一个文件的顶部,而 tail 将显示一个文件的底部,但 sed 允许从任意位置取出想要的任意内容。
6 脚本文件
sed 工具允许您创建一个脚本文件,其中包含从该文件而不是在命令行进行处理的命令,并且 sed 工具通过 "-f" 选项来引用。通过创建一个脚本文件,您能够一次又一次地重复运行相同的操作,并指定比每次希望从命令行进行处理的操作详细得多的操作。
注意当调用 "-f" 选项时,在源文件内或命令行中不使用撇号。脚本文件,也称为源文件,对于想重复多次的操作和从命令行运行可能出错的复杂命令很有价值。编辑源文件并修改一个字符比在命令行中重新输入一条多行的项目要容易得多。
7 替换命令
Sed最常用的命令之一是用一个值替换另一个值。用来实现这一目的的操作的命令部分语法是:
's/{old value}/{new value}/'典型示例:
- 下面演示了如何非常简单地将 "tiger" 修改为 "wolf":
$ echo The tiger cubs will meet on Tuesday after school | sed 's/tiger/wolf/' The wolf cubs will meet on Tuesday after school
- sed 还可以用来修改记录字段分隔符。例如,以下命令将把所有的 tab 修改为空格:
sed 's// /g'
- 假定希望用 "2" 来替换 "1",但仅在单词 "two" 之后才作替换,而不是每一行的所有位置。通过指定在给出替换命令之前必须存在一次匹配,可以实现这一点:
sed '/two/ s/1/2/' sample_one
8 指定要处理的行
编辑器默认查看输入到流编辑器中的每一行,且默认在输入到流编辑器中的每一行上进行编辑。这可以通过在发出命令之前指定约束条件来进行修改。例如,只在此示例文件的输出的第 5 和第 6 行中用 "2" 来替换 "1",命令将为:
sed '5,6 s/1/2/' sample_one
9 删除行
用一个值替换另一个值远非流编辑器可以执行的唯一功能。它还具有许多的潜在功能,在我看来第二种最常用的功能是删除。删除与替换的工作方式相同,只是它删除指定的行(如果您想要删除一个单词而不是一行,不要考虑删除,而应考虑用空的内容来替换它—s/cat//)。
该命令的语法是:
'{what to find} d'从 sample_one 文件中删除包含 "two" 的所有行:
sed '/two/ d' sample_one
从显示屏中删除前三行,而不管它们的内容是什么:
sed '1,3 d' sample_one
删除开头是 "two" 行
sed '/^two/ d' sample_one
删除文件中的所有空白行。
sed '/^$/ d' {filename}
删除文件中从第一行直到第一个空行之间的行:
sed '1,/^$/ d' {filename}
10 添加和插入文本
可以结合使用 sed 和 "a" 选项将文本添加到一个文件的末尾。实现方法如下:
$ sed '$a\ > This is where we stop > the test' sample_one
在该命令中,美元符号 ($) 表示文本将被添加到文件的末尾。反斜线 () 是必需的,它表示将插入一个回车符。如果它们被遗漏了,则将导致一个错误,显示该命令是错乱的;在任何要输入回车的地方您必须使用反斜线。
要将这些行添加到第 4 和第 5 个位置而不是末尾,则命令变为:
$ sed '3a\ > This is where we stop > the test' sample_one
您可以选择插入而不是添加(如果您希望这样的话)。这两者的区别是添加跟在指定的行之后,而插入从指定的行开始。当用插入来代替添加时,只需用 "i" 来代替 "a",如下所示:
$ sed '3i\ > This is where we stop > the test' sample_one
11 读写文件
重定向输出的功能已经演示过了,但需要指出的是,在编辑命令运行期间可以同步地读入和写出文件。例如,执行替换,并将 1-3 行写到名称为 sample_three 的文件中:
$ sed ' > /two/ s/1/2/ > /three/ s/1/3/ > 1,3 w sample_three' sample_one
12 修改命令
除了替换项目之外,还可以将行从一个值修改为另一个值。要记住的是,替换是对字符逐个进行,而修改功能与删除类似,它影响整行:
$ sed '/two/c\ > We are no longer using two' sample_one one 1 We are no longer using two three 1 one 1 We are no longer using two We are no longer using two three 1
修改命令与替换的工作方式很相似,但在范围上要更大些—将一个项目完全替换为另一个项目,而无论字符内容或上下文。夸张一点讲,当使用替换时,只有字符 "1" 被字符 "2" 替换,而当使用修改时,原来的整行将被修改。在两种情况下,要寻找的匹配条件都仅为 "two"。
13 相反操作
对于大多数 sed 命令,详细说明各种功能要进行何种修改。利用感叹号,可以在除指定位置之外的任何地方执行修改—与默认的操作完全相反。
例如,要删除包含单词 "two" 的所有行,操作为:
$ sed '/two/ d' sample_one one 1 three 1 one 1 three 1
而要删除除包含单词 "two" 的行之外的所有行,则语法变为:
$ sed '/two/ !d' sample_one two 1 two 1 two 1
14 提前退出
sed 默认读取整个文件,并只在到达末尾时才停止。不过,您可以使用退出命令提前停止处理。只能指定一条退出命令,而处理将一直持续直到满足调用退出命令的条件。
例如,仅在文件的前五行上执行替换,然后退出:
$ sed ' > /two/ s/1/2/ > /three/ s/1/3/ > 5q' sample_one
在退出命令之前的项目可以是一个行号(如上所示),或者一条查找/匹配命令:
$ sed ' > /two/ s/1/2/ > /three/ s/1/3/ > /three/q' sample_one
您还可以使用退出命令来查看超过一定标准数目的行,并增加比 head 中的功能更强的功能。例如,head 命令允许您指定您想要查看一个文件的前多少行—默认数为 10,但可以使用从 1 到 99 的任意一个数字。如果您想查看一个文件的前 110 行,您用 head 不能实现这一目的,但用 sed 可以:
sed 110q filename15 标签和注释
可以在 sed 脚本文件中放置标签,这样一旦文件变得庞大,可以更容易地说明正在发生的事情。存在各种各样与这些标签相关的命令,它们包括: : 冒号表示一个标签名称。例如:
:HERE
以冒号开始的标签可以由 "b" 和 "t" 命令处理。
b {label} 充当 "goto" 语句的作用,将处理发送至前面有一个冒号的标签。例如,
b HERE
将处理发送给行 :HERE
如果紧跟 b 之后没有指定任何标签,则处理转至脚本文件的末尾。
基本上 , 函数参数 t 与 函数参数 b 的功能类似 , 除了在执行 t 的 branch 前 , 会先去测试其前的替换指令有没有 执行替换成功,如成功 , 则执行 branch ; 不成功 , 则不 branch , 而继续执行下一个编辑指令。
# 符号作为一行的第一个字符将使整行被当作注释处理。注释行与标签不同,不能使用 b 或 t 命令来转到注释行上。
16 函数参数详解
16.1 s
函数参数 s 表示替换(substitute)文件内字符串。其指令格式如下 :
[address1[,address2]] s/pattern/replacemen/[flag]
对上述格式有下面几点说明 :
- 函数参数 s 最多与两个地址参数配合。
- pattern : 它为 reguler expression 字符串。它表示文件中要被替换的字符串。
- replacement : 它为一般字符串。但其内出现下列字符有特别意义 :
- & : 代表其前 pattern 字符串。例如
sed -e 's/test/& my car/' 资料文件名
- 指令中,& 代表 pattern 字符串 "test"。故执行后,数据文件的 "test" 被替换成 "test my car"。
- \n : 代表 pattern 中被第 n 个 \( 、\)(参照[附录 A]) 所括起来的字符串。例如
sed -e 's/\(test\) \(my\) \(car\)/[\2 \3 \1]/' 资料文件名
- 指令中,\1 表示 "test"、\2 表示 "my"、\1 表示 "car" 字符串。故执行后,数据文件的 "test my car" 被替换成 "[my car test]"。
- \ : 可用它来还原一些特殊符号(如上述的 & 与 \ )本身字面上的意义,或用它来代表换行。
- flag : 主要用它来控制一些替换情况 :
- 当 flag 为 g 时,代表替换所有符合(match)的字符串 。
- 当 flag 为十进制数 m 时,代表替换行内第 m 个符合的字符串。
- 当 flag 为 p 时,代表替换第一个符合 pattern 的字符串后,将数据输出标准输出文件。
- 当 flag 为 w wfile 时,代表替换第一个符合 pattern 的字符串后,输出到 wfile 檔内(如果 wfile 不存在,则会重新开启名为 wfile 的档案)。
- 当没有 flag 时,则将资料行内第一个符合 pattern 的字符串以 replacement 字符串来替换 。
- delimiter : 在 "/pattern/replace/[flag] " 中 "/" 被当成一 delimiter。除了空白(blank)、换行(newline) 之外,使用者可用任何字符作为 delimiter。例如下述编辑指令
s#/usr#/usr1#g
- 上述命令中 # 为 delimiter 。如果用 "/" 做 delimiter,则 sed 会将 pattern 与 replacement 中的 "/" 当成delimiter 而发生错误。
16.2 d
函数参数 d 表示删除数据行,其指令格式如下:
[address1[ ,address2]] d
对上述格式有下面几点说明:
- 函数参数 d 最多与两个地址参数配合。
- sed 执行删除动作情况如下 :
- 将 pattern space 内符合地址参数的数据删除。
- 将下一笔资料读进 pattern space 。
- 重新执行 sed script。
16.3 a
函数参数 a 表示将资料添加到文件中。其指令格式如下:
[address1] a\ 使用者所输入的数据
对上述格式有下面几点说明:
- 函数参数 a 最多与一个地址参数配合。
- 函数参数 a 紧接着 "\" 字符用来表示此行结束 , 使用者所输入的数据必须从下一行输入。如果数据超过一行 , 则须在每行的结尾加入"\"。
- sed 执行添加动作情况如下 : 当 pattern space 内数据输出后 , sed 跟着输出使用者所输入的数据。
16.4 i
函数参数 i 表示将资料插入文件中。其指令格式如下:
[address1] i\ 使用者所输入的数据
对上述格式有下面几点说明:
- 函数参数 i 最多与一个地址参数配合。
- 函数参数 i 紧接着 "\" 字符用来表示此行结束 , 使用者所输入的数据必须从下一行输入。如果数据超过一行 , 则须在每行的结尾加入"\"。
- sed 执行插入动作的情况如下 : 在 pattern space 内数据输出前 , sed 先输出使用者所输入的数据。
16.5 c
函数参数 c 表示改变文件中的数据。其格式如下:
[address1[ ,address2]]c\ 使用者所输入的数据
对上述格式有下面几点说明:
- 函数参数 c 最多与两个地址参数配合。
- 函数参数 c 紧接着 "\" 字符用来表示此行结束 , 使用者所输入的数据必须从下一行输入。如果数据超过一行 , 则须在每行的结尾加入"\"。
- sed 执行改变动作的情况 : 在 pattern space 内数据输出时 , sed 改变它成为使用者所输入的数据。
16.6 p
17 参见
- Sed - An Introduction and Tutorial, Bruce Barnett. Bruce Barnett. 2010-7-16 10:11:55.
- Sed学习笔记. Jim. 2008-03-04.
- 刘刚. sed 手册. 2008-05-07.