sed

数据流编辑器


语法格式

sed [-cnrsu] [-i[suffix]] [-l n] [--follow-symlinks] [--posix]
script [files]
sed [-cnrsu] [-e script] [-f script] [-i[suffix]] [-l n]
[--follow-symlinks] [--posix] [files]
sed [--help] [--version]

命令简介

sed是一个数据流编辑器,用于过滤和转换文本数据。sed采用一次性处理的方式,一边读取指定文件的输入数据流,一边施以基本的行编辑命令,实现文本数据的过滤与转换,把处理结果写到标准输出。

其中,files是欲编辑的文本文件的路径名。如果指定了多个输入文件,sed将会依次读取和编辑每一个文件。如果未指定输入文件,或指定的文件名为“-”,则读取标准输入。script是一组sed编辑命令,为保险起见,整个编辑命令前后应加引号。

作为脚本参数,编辑命令可以在命令行上直接提供,可以由“-e”选项指定,也可以取自“-f”选项指定的脚本文件。如果未指定“-e”或“-f”选项,sed把第一个非选项参数作为编辑命令脚本,把后续的其他参数作为输入文件解释和处理。

此外,“-e”和“-f”选项可以同时存在,也可以重复指定多个脚本文件。其中的所有编辑命令依序组合在一起,最终形成一个完整的sed编辑命令。

命令选项

-c, --copy  在“-i”选项指定的模式中,采用复制而非重新命名的方式处理临时文件与输入文件。

-e script, --expression=script  把指定的编辑命令加到处理输入文件的编辑命令集合中。script可以含有多个sed编辑命令,每行一个,整个编辑命令前后加引号。

-f script, --file=script  把指定脚本文件script中的编辑命令加到处理输入文件的编辑命令集合中。脚本文件script含有sed编辑命令,每行一个。

-i[suffix], --in-place[=suffix]  编辑当前的输入文件,把处理结果写入新建的临时文件中(而非标准输出)。编辑完成之后,把临时文件重新命名为原始的输入文件(如果提供了扩展名suffix,在重新命名之前首先创建备份文件。注意,suffix与“-i”之间不能加空格)。指定“-i”选项也蕴含着同时指定了“-s”选项。

-l n, --line-length=n  指定sed的l(L的小写字母)命令使用的默认行宽。0意味着禁止把长行延续到下一行。如果未指定行宽,默认的行宽为70个字符位置。

-n, --quiet, --silent  压缩输出信息,仅显示sed编辑命令p明确指明的输出内容。

-r, --regexp-extended  使用扩展的正则表达式。

-s, --separate  通常,sed把多个输入文件看作一个连续的输入数据流,允许跨文件编辑。“-s”选项表示单独处理每一个文件。

-u, --unbuffered  尽可能使用最小的输入输出缓冲区,以便尽快看到处理后的结果。

--follow-symlinks  处理符号链接文件时使用其引用的文件。

--posix  禁止使用GNU的扩充特性。

脚本与编辑命令

sed脚本由一组sed编辑命令组成,每行一个编辑命令,每个编辑命令具有下列语法格式:

[address [, address]] command [ arguments ]

其中,address可以是一个十进制数值,表示输入数据的地址或行号,可以是一个美元符号,表示最后一行输入数据,也可以是一个正则表达式,表示匹配的数据行。command是sed编辑命令。arguments是编辑命令的参数。

在常规的操作过程中,sed采用循环的方式,逐行读取输入数据,然后把数据复制到模式空间(pattern space),再根据sed编辑命令的地址,依次施加匹配的编辑命令,最后,把模式空间的处理结果写到标准输出(除非指定了“-n”选项),删除模式空间。

此外,某些sed命令还使用收容空间(hold space)保存所有或部分模式空间,以便之后能够随时获取数据。

地址

执行sed命令时,地址可以省略,这意味着当前命令施加于所有的输入数据行。如果给定一个地址,表示sed命令仅作用于匹配指定地址的输入数据行。如果给定两个地址,sed命令可用于匹配指定地址范围内的所有输入数据行。

在单地址或双地址之后与sed编辑命令之前,可以插入一个感叹号“!”,表示相应的命令仅适用于不匹配指定地址或地址范围的其他数据行。

对于地址范围而言,有两件事情需要注意:addr1对应的数据行总是sed命令作用的对象,即使addr2小于addr1;如果addr2是一个正则表达式,sed也不会测试addr1对应的数据行。

单地址寻址

number  选择指定行号的数据行。

first~step  选择从first行开始每第step行的数据。例如,“sed -n 1~2p”将会显示输入数据流中的所有奇数行的数据。起始行first可以是0。

$  选择最后一行。

/regexp/  选择匹配正则表达式regexp的所有数据行。

\%regexp%  选择匹配正则表达式regexp的所有数据行。其中,%可以是任何字符。

注意,“/regexp/”与“\%regexp%”后面可以附加一个大写字母“I”,表示匹配时忽略大小写字母的差别。

双地址寻址

addr1,addr2  选择从第addr1行开始直至第addr2行的所有数据行。

addr1,+n  选择第addr1行与随后的n行数据。

addr1,~n  选择第addr1行直至某一输入数据行的行号是n的倍数之间的所有数据行。

0,/regexp/  “0,/regexp/”类似于“1,/regexp/”,都表示从第一个输入数据行开始匹配正则表达式。其差别是,在“0,/regexp/”的情况下,如果regexp 匹配第一行,则整个范围匹配结束。而在“1,/regexp/”的情况下,即使regexp 匹配第一行,也只是范围的开始,还需要继续检索,直至出现第二个匹配行才能构成一个范围。

0地址命令

: label  插入一个标号,供b和t命令跳转。

#comment  注释行,直至换行符为止。

}  终结一个{ }块。

0或单地址命令

=  显示当前的行号。

a\

text  追加文本数据text。在读取下一行输入数据前,把text写到标准输出。如果text包含多行数据,除了最后一行,每一行后面都要附加一个转义符号“\”。注意,i与c命令中的text也是如此处理。a(包括i和c)与“\”之间没有空格。

i\

text  插入文本数据text。把text写到标准输出。

q [exit-code]  停止任何数据处理动作,立即退出sed脚本(之前还需要输出当前的模式空间,除非禁用了自动输出功能)。

Q [exit-code]  停止任何数据处理动作,立即退出sed脚本。

r file  在读取下一行输入数据之前,读取指定文件中的全部数据,然后写到标准输出。

R file  在读取下一行输入数据之前,从指定的文件中读取一行数据,然后写到标准输出。每次调用R命令时,仅读取一行数据,输出一行数据。

双地址命令

{  开始一个编辑命令块(以“}”结束)。

b label  跳转到指定的标号位置。如果省略了标号,跳转到脚本的最后位置。

t label  如果已经对最近读取的输入数据成功地执行了s替换命令,或执行了t或T命令,跳转到指定的标号位置。如果省略了标号,跳转到脚本的最后位置。

T label  如果没有对最近读取的输入数据成功地执行了s替换命令,或执行了t或T命令,跳转到指定的标号位置。如果省略了标号,跳转到脚本的最后位置。

c\

text  使用提供的数据text替换选择的行。删除模式空间,把text写到标准输出,开始下一轮处理。

d  删除模式空间,开始下一轮处理。

D  删除模式空间中的数据直至遇到第一个嵌入的换行符为止。开始下一轮处理,但跳过读取输入数据的步骤(如果模式空间仍存在数据)。

h  把模式空间中的数据复制到收容空间。

H  把模式空间中的数据追加到收容空间。

g  把收容空间中的数据复制到模式空间。

G  把收容空间中的数据追加到模式空间。

x  交换收容空间与模式空间中的数据内容。

l  以明显的形式,在标准输出上列出当前模式空间中的数据(不可打印的字符以转义的八进制数值显示,超长的数据行可延续到下一行)。

l width  以明显可视的形式,在标准输出上列出当前模式空间中的数据(不可打印的字符以转义的八进制数值显示,以指定的行宽为准,超长的数据行可延续到下一行)。

n  读取下一行输入数据,把数据复制到模式空间。

N  读取下一行输入数据,把数据追加到模式空间。

p  显示当前的模式空间。

P  显示当前模式空间中的数据直至遇到第一个嵌入的换行符。

s/re/sub/[flag]  使用正则表达式re匹配模式空间,如果成功,使用sub替换匹配的部分。sub中可以包含特殊字符“&”,引用模式空间中的匹配部分,也可以包含特殊的转义字符“\1”至“\9”,引用匹配正则表达式re中相应子表达式匹配的部分。flag是选用的标志,可以是下列常用的一个或多个标志,用于限定替换动作:

g  表示替换匹配指定表达式的所有字符串,而不是仅替换第一个匹配者。

n  n是一个数字,表示仅替换第n个匹配指定表达式的字符串。

p  如果替换发生,显示替换后的结果。

w file  如果替换发生,把替换后的结果写入指定的文件。

I(或i)  在执行模式匹配时,忽略大小写字母的差异。

w file  把当前的模式空间写到指定的文件中。

W file  把当前模式空间的第一行写到指定的文件中。

y/src/dest/  把模式空间中匹配src的字符映射为dest中的相应字符。

正则表达式

正则表达式是一种模式,用于描述检索对象中欲匹配的字符串。最简单的模式是由普通字符组成的字符串,用于匹配检索对象中的相应字符串。

正则表达式的威力来自模式中的特殊字符及其解释方式,能够实现复杂的匹配。下面是sed支持的正则表达式及其简单说明:

char  单个普通字符匹配自身。例如,abcdefg匹配字符串abcdefg。

*  匹配前一项0次或多次。前一项必须是一个普通字符、一个加了转义符号的特殊字符、一个句点“.”、一个组合的正则表达式或一个方括号表达式。例如,a*b匹配0个或多个a,最后跟随一个b。ap*le匹配ale或apple等。

\+  类似于“*”,但匹配前一项1次或多次。例如,“a\+b\+”匹配一个或多个a,后跟随一个或多个b,其中ab是最短的匹配,其他可以是aab或abbb等。

\?  类似于“*”,但匹配前一项0次或1次。如a\?b匹配b或ab,script(\.sh)?匹配script或script.sh等。

\{m\}  类似于“*”,但恰好匹配m次。m是一个整数。例如,“[0-9]\{5\}”表示恰好匹配5位数字。

\{m,n\}  类似于“*”,但至少匹配前一项m次,不超过n次(包括mn本身)。

\{m,\}  类似于“*”,但匹配前一项m次或m次以上。

\(re\)  把圆括号中的表达式re组合成一个整体,称作子表达式,用于后缀运算符,如“\(abcd\)*”表示检索0个或多个字符串abcd,而“abcd*”只能检索“abc”与后随的0个或多个字符“d”。此外,子表达式的一个重要用途是反向引用,参见“\digit”的说明。一个表达式中可以存在多个子表达式,子表达式从1开始编号。

.  匹配任何一个字符,包括换行符。例如,“.*”匹配字符串中的所有字符,或者说匹配任何一个字符串,包括空串。“.\+”匹配任何一个字符串,但每个字符串至少必须包含一个字符,即不匹配空串。

^  匹配模式空间行首的空串,即匹配出现在模式空间行首的任何字符或字符串。例如,“^main.*(.*)”匹配一个位于行首的字符串main,紧随一对圆括号(“n”、“(”和“)”不需要紧连在一起)。“^#”匹配一个以“#”开始的位于行首的字符串,如“#include”。作为一个特殊字符,“^”也可以出现在正则表达式的前面,位于“\(”或“\|”之后。

$  匹配模式空间行尾的空串。作为一个特殊字符,“$”也可以出现在正则表达式的后面,位于“\)”或“\|”之前。例如,“\\$”表示匹配任何以单个反斜线“\”(行延续符)结尾的数据行。“\.$”表示匹配任何以句点“.”结尾的数据行。

[list]  枚举的字符集合,表示匹配括号中的任何一个字符。例如,“[aeiou]”表示匹配所有的元音字母。在定义字符集合时,可以使用“char1-char2”的形式表示一个字符范围,如“[a-zA-Z0-9]”表示匹配任何ASCII字母或数字。此外,如果字符集合中出现特殊字符“$”、“*”、“.”、“[”或“\”(包括不在第一个字符位置的“^”),均作普通字符处理,例如,“[\*]”表示只匹配字符“\”或“*”,因为这里的“\”不是转义符号。此外,字符集合还可以容纳“[:class:]”、“[=a=]”或“[.ch.]”形式的字符类、等价类和排序符号等,如“[:alnum:]”表示所有的字母与数字。此外,如果POSIXLY_CORRECT环境变量没有设置,特殊的转义字符(如“\n”和“\t”等)也可以出现在方括号字符集合中。

[^list]  字符集合前的“^”符号意味着反其意而行之,表示不匹配方括号内的任何字符,而是匹配不在指定字符集合范围内的任何字符。例如,“[^[:space:]]\+”表示匹配由一个或多个非空白字符(空格或制表符)组成的字符串。

re1\|re2  匹配re1re2。此外,利用子正则表达式还可以实现复杂的匹配。例如,“(E\|e)xit”表示匹配Exit或exit。

re1re2  匹配正则表达式re1re2的连接。

\digit  反向引用(back reference),其中digit是一个数字,表示匹配正则表达式中第digit个子表达式“\(...\)”选择的字符串。例如,“^\(.*\)\n\1$”能够匹配两个等同的子串中间加换行符组成的字符串。

\char  匹配单个特殊字符,其中char是“$”、“*”、“.”、“[”、“\”或“^”等。例如,“\$”表示仅匹配由单个美元符号组成的字符串。

在正则表达式中,还可以使用下列转义字符,以匹配不可打印的特殊字符:

\a  匹配警示音。

\f  匹配换页符。

\n  匹配换行符。

\r  匹配回车字符。

\t  匹配制表符。

\v  匹配纵向制表符。

\cX  匹配Ctrl-X,X可以是任何字符。

\dXXX  匹配十进制ASCII编码表示的字符。

\oXXX  匹配八进制ASCII编码表示的字符。

\xXX  匹配十六进制ASCII编码表示的字符。

此外,sed正则表达式还支持下列特殊的字符类:

\w  匹配能够组成单字的任何字符,包括任何字母、数字或下画线。

\W  匹配非单字构成字符的任何字符,即除字母、数字和下画线之外的其他任何字符。

\b  匹配单字左右边缘的空串。例如,“\ba”能够匹配age或air等单词,“e\b”能够匹配same或come等单词。

\B  匹配单字非边缘字符位置的空串。例如,“\Bm”或“m\B”能够匹配same或come等单词。

\`  匹配模式空间起始字符位置的空串。类似于常规数据行匹配的“^”字符。

\’  匹配模式空间结束字符位置的空串。类似于常规数据行匹配的“$”字符。

注意,正则表达式的匹配采用贪心方式。从左到右,从第一个匹配的字符开始,如果出现两个或更多的匹配者,最终选择的是最长者。

应用实例

1. 把指定的设置追加到.bash_profile文件(为保险起见,保留一个备份.bash_profile.old)。

$ sed –i.old -e '$ a\
LANG=C; export LANG' .bash_profile
$

2. 模拟“wc -l”命令,计数指定文件的行数。

$ sed -n '$=' /etc/profile
68
$

索引:A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z