sed
编程范型 | 脚本 |
---|---|
設計者 | 李·E·麥克馬洪 |
发行时间 | 1974年 |
實作語言 | C |
網站 | 无 |
啟發語言 | |
ed | |
影響語言 | |
Chomski, Perl, AWK |
sed(意为流编辑器,源自英语“stream editor”的缩写)是一个使用简单紧凑的编程语言来解析和转换文本Unix实用程序。
sed由贝尔实验室的李·E·麥克馬洪于1973年至1974年开发, [1] 并且现在大多数操作系统都可以使用。 [2] sed基于交互式编辑器ed(“editor”,1971)和早期qed(“quick editor”,1965-66)的脚本功能。sed是最早支持正则表达式的工具之一,至今仍然用于文本处理,特别是用于替换命令。用于纯文本字符串操作和“流编辑”的常用工具还有AWK和Perl 。
历史
sed是为命令行处理数据文件而构建的早期Unix命令之一,首次出现在Version 7 Unix中 。[3]它很自然地演变成为流行的grep命令的后继。[4] 最初的动机与grep(g/re/p)的替换类似,因此称为“g/re/s”。[3] 考虑到这样的话还会出现针对每个命令的专用程序,例如g/re/d,李·E·麥克馬洪编写了一个通用的面向行的流编辑器,该编辑器后来成为了sed。[4] sed的语法,特别是把/
用于模式匹配,把s///
用于替换,起源于sed的前身ed(当时ed很常用)[4] 而且正则表达式语法影响了其他一些语言,特别是ECMAScript和Perl。后来,更强大的语言AWK问世,这些工具相互补充,让通过shell脚本完成强大的文本处理成为可能。sed和AWK常被认为Perl的祖先和灵感来源,并且影响了Perl的语法和语义,尤其影响了匹配和替换运算符。
GNU sed添加了一些新功能,包括文件的就地编辑 。Super-sed 是sed的扩展版本,包含与Perl兼容的正则表达式。sed的另一变体minised ,最初埃里克·雷蒙把4.1BSD sed通过逆向工程写成,目前由René Rebe维护。在GNU计划基于新的GNU正则表达式库编写了新版本的sed之前,GNU计划一直使用minised。当前minised包含一些BSD sed的扩展,但不像GNU sed那样功能丰富。它的优点是速度快,占用的内存少。它用于嵌入式系统,是Minix提供的sed版本。
工作模式
sed是一个面向行的文本处理实用程序:它从输入流或文件中逐行读取文本到一个称为模式空间 的内部缓冲区。每读一行开始一个循环 。对于模式空间,sed会应用sed脚本 指定的一个或多个操作。sed实现了一种编程语言,其中包含大约25个指定文本操作的命令 。对于每个输入行,在运行脚本之后,sed通常输出模式空间(由脚本修改的行),然后从下一行再次开始循环。其他脚本结束行为可通过sed选项和脚本命令获得,例如d
删除模式空间,q
退出,N
立即将下一行添加到模式空间,等等。因此,sed脚本对应于循环体,循环体遍历流的行,其中循环本身和循环变量(当前行号)是隐式的并由sed维护。
可以在命令行上指定sed脚本( -e
选项),也可以从单独的文件中读取( -f
选项)。sed脚本中的命令可以采用行号或正则表达式的作为地址 。该地址确定决定命令何时运行。例如,2d
将仅在第二个输入行上运行d
(删除)命令(打印除第二个输入行之外的所有行),而/^ /d
将删除以空格开头的所有行。一些单独的特殊缓冲区,即保持空间,可以由几个sed命令使用,用于在循环之间保持和累积文本。sed的命令语言只有两个变量(“保持空间”和“模式空间”)和类似GOTO的分支功能;然而,这种语言是图灵完备的,[5][6] 用深奥sed脚本甚至写得出推箱子、打砖块[7]、国际象棋[8]和俄罗斯方块[9]等游戏。
为输入流的每一行执行一次主循环,在输入的每一行上计算sed脚本。sed脚本的每一行都是模式-动作对,指示着要匹配的模式和要执行的操作,可以将其重新组合为条件语句。因为主循环、工作变量(模式空间和保持空间)、输入和输出流以及默认操作(复制行到模式空间、打印模式空间)是隐式的,所以可以编写简洁的单行程序。例如,以下sed程序:
10q
将打印输入的前10行,然后停止。
用法
替换命令
下面的示例显示了sed用于替换的典型(也是最常见的)用法。这种用法确实是sed的最初动机:[4]
sed 's/regexp/replacement/g' inputFileName > outputFileName
在某些版本的sed中,表达式的前面必须加上-e
,以表示后面跟着一个表达式。s
表示替换,而g
表示全局,这意味着行中的所有匹配项都将被替换。要搜索的正则表达式(即pattern)放在第一个分隔符号(此处为斜杠)之后,而要替换成的字符串跟在第二个分隔符号后面。斜杠(/
)是传统的符号,起源于ed中的“搜索”字符,但其实在pattern和替换文本中都未出现的任何其他符号都可以用作分隔符号,使其可读性更强;这有助于避免“倾斜牙签综合征”。
替换命令源自ed中的搜索-替换,实现了简单的解析和模板化 。regexp
提供模式匹配和通过子表达式保存文本的功能,而replacement
可以是纯文本,也可以是包含“完全匹配”&
,或第n 个子表达式(从\1
到\9
)这种特殊转义序列的格式字符串。例如, sed -r "s/(cat|dog)s?/\1s/g"
用“cat”或“dog”替换所有出现的“cats”或“dogs”,且不重覆复制出原文內已有的“s”:在正则表达式中,(cat|dog)
是第一个(也是唯一)保存的子表达式,格式字符串中的\1
将其替换到输出里。
其他sed命令
除了替换之外,使用大约25个sed命令可以进行其他形式的简单处理。例如,下面使用d 命令删除空行或只包含空格的行:
sed '/^ *$/d' inputFileName
本例使用了下列正则表达式元字符(sed支持所有正则表达式):
- 脱字符(
^
)匹配行首。 - 美元符号(
$
)匹配行尾。 - 星号(
*
)匹配前一个字符零次或多次出现。
可以有很复杂的sed结构,让sed用作一种简单但高度专业化的编程语言。例如,可以通过使用标签(冒号后跟字符串)和分支指令b
来管理控制流程。指令b
后跟有效的标签名称,将把处理流程移动到该标签后面的块。
sed用作过滤器
在Unix下,sed通常用作管道中的过滤器:
$ generateData | sed 's/x/y/g'
也就是说,诸如“generateData”之类的程序生成数据,然后用sed把x替换成y。例如:
$ echo xyz xyz | sed 's/x/y/g'
yyz yyz
基于文件的sed脚本
将几个sed命令(每行一个命令)放入脚本文件(例如subst.sed
)中然后使用-f
选项从文件中运行命令(例如s/x/y/g
)通常很有用:
sed -f subst.sed inputFileName > outputFileName
可以在脚本文件中放置任意数量的命令,使用脚本文件也可以避免shell转义或替换的问题。
这样的脚本文件可以直接从命令行执行,方法是在其前面加上一个包含sed命令的"shebang行",并为该文件分配可执行权限。例如,可以使用以下内容创建文件subst.sed
:
#!/bin/sed -f
s/x/y/g
然后,当前用户可以使用chmod
命令使文件可执行:
chmod u+x subst.sed
然后可以直接从命令行执行该文件:
subst.sed inputFileName > outputFileName
就地编辑
GNU sed中引入的-i
选项允许就地编辑文件(实际上,在后台创建了一个临时输出文件,然后将原始文件替换为临时文件)。例如:
sed -i 's/abc/def/' fileName
示例
Hello, world! 例子
# convert input text stream to "Hello, world!"
s/.*/Hello, world!/
q
这个“Hello, world!”脚本位于文件(如script.txt)中,并使用sed -f script.txt inputFileName
调用,其中“inputFileName”是输入文本文件。脚本将“inputFileName”第1行更改为“Hello, world!”然后退出,在sed退出之前打印结果。第1行后的任何输入行都不会被读取,也不会被打印。唯一的输出是“Hello, world!”。
这个例子强调了sed的许多关键特性:
- sed是独一无二的。没有其他“Hello, world!”例子与之相似。
- 典型的sed程序相当简短。
- sed脚本可以有注释(以
#
符号开头的行)。 s
(替换)命令是最重要的sed命令。- sed允许使用
q
(退出)等命令进行简单编程。 - sed使用正则表达式,例如
.*
(任何字符的零个或多个)。
其他简单的例子
下面是各种sed脚本;可以把它们作为参数传递给sed,或者放入一个单独的文件并通过-f
执行或通过使脚本本身可执行来执行。
要把文件中某个单词(例如IRC密码)替换为“REDACTED”,并保存结果:
sed -i s/yourpassword/REDACTED/ ./status.freenode.log
要删除包含“yourword”一词的所有行( 地址 为“/yourword/”):
/yourword/ d
要删除所有“yourword”这个词:
s/yourword//g
要同时从文件中删除两个单词:
s/firstword//g
s/secondword//g
为了在一行表示前面的示例,比如在命令行输入时,可以通过分号连接两个命令:
sed "s/firstword//g; s/secondword//g" inputFileName
多行处理示例
在下一个示例中,sed(通常仅在一行上工作)会在某一行的后一行以一个空格打头的情况下删除换行符。 请考虑以下文本:
This is my dog, whose name is Frank. This is my fish, whose name is George. This is my goat, whose name is Adam.
下面的sed脚本会将上面的文本转换为以下文本。请注意,该脚本仅影响以空格开头的输入行:
This is my dog, whose name is Frank. This is my fish, whose name is George. This is my goat, whose name is Adam.
使用的脚本是:
N s/\n / / P D
这段脚本应按如下理解:
- (
N
)将下一行添加到模式空间; - (
s/\n / /
)查找一个换行符后跟一个空格,替换为一个空格; - (
P
)打印模式空间的顶行; - (
D
)从模式空间中删除顶行并再次运行脚本。
这可以通过分号在一行中表示出来:
sed 'N; s/\n / /; P; D' inputFileName
限制和替代方案
虽然sed具有简单性和局限性,但对于大量用途而言,它的功能已经足够强大。对于更复杂的处理,可以使用更强大的语言,如AWK或Perl或者PowerShell。虽然使用保持缓冲区理论上可以进行任意复杂的转换,但如果转换行的方式比正则表达式提取和模板替换更复杂,则使用一般会使用上面提到的更强大的语言。
相反,对于更简单的操作,grep (打印匹配模式的行),head(打印文件的第一部分),tail(打印文件的最后部分)和tr(翻译或删除字符)等专门的Unix实用程序通常更可取。对于设计用于执行的特定任务,此类专用实用程序通常比较一般的解决方案(如sed)更简单、清晰和快速。
ed/sed命令和语法继续用于派生程序,例如文本编辑器vi和vim。sam/ssam与ed/sed类似,其中sam是Plan 9编辑器,ssam是它的流接口,其功能类似于sed。
注释
- ^ 在命令行使用中,表达式周围的引号不是必需的,只有在shell不会将表达式解释为单个字(标记)时才需要。由于脚本
s/x/y/g
没有歧义,所以generateData | sed s/x/y/g
工作正常。然而,为了清楚起见,通常是要写引号的,特别是对于有空格的时候(例如,'s/x x/y y/'
)。大多数情况下,使用单引号是为了避免shell将$
解释为shell变量。使用双引号,如"s/$1/$2/g"
,是为了让shell替换命令行参数或其他shell变量。
参考文献
- ^ The sed FAQ, Section 2.1. [2013-05-21]. (原始内容存档于2018-06-27).
- ^ The sed FAQ, Section 2.2. [2013-05-21]. (原始内容存档于2018-06-27).
- ^ 3.0 3.1 McIlroy, M. D. A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (技术报告). CSTR. Bell Labs. 1987 [2018-11-10]. 139. (原始内容存档 (PDF)于2019-11-30).
- ^ 4.0 4.1 4.2 4.3 On the Early History and Impact of Unix. [2018-11-10]. (原始内容存档于2017-09-07).
A while later a demand arose for another special-purpose program, gres, for substitution: g/re/s. Lee McMahon undertook to write it, and soon foresaw that there would be no end to the family: g/re/d, g/re/a, etc. As his concept developed it became sed…
- ^ Implementation of a Turing Machine as Sed Script. [2018-11-10]. (原始内容存档于2018-02-20).
- ^ Turing.sed. [2018-11-10]. (原始内容存档于2018-01-16).
- ^ The $SED Home - gamez. [2009-04-20]. (原始内容存档于2006-02-08).
- ^ bolknote/SedChess. GitHub. [2018-11-10]. (原始内容存档于2018-12-02).
- ^ Sedtris, a Tetris game written for sed. [2018-11-10]. (原始内容存档于2018-12-02).
扩展阅读
- 贝尔实验室的第八版(约1985年)Unix sed(1)手册页(页面存档备份,存于互联网档案馆)
- GNU sed(1)手册页
- Dale Dougherty & Arnold Robbins. sed & awk 2nd. O'Reilly. March 1997 [2018-11-10]. ISBN 1-56592-225-5. (原始内容存档于2018-11-02).
- Arnold Robbins. sed and awk Pocket Reference 2nd. O'Reilly. June 2002 [2018-11-10]. ISBN 0-596-00352-8. (原始内容存档于2018-11-11).
- Peter Patsis. UNIX AWK and SED Programmer's Interactive Workbook (UNIX Interactive Workbook). Prentice Hall. December 1998 [2018-11-10]. ISBN 0-13-082675-8. (原始内容存档于2020-04-09).
- Daniel Goldman. Definitive Guide to sed. EHDP Press. February 2013 [2018-11-10]. ISBN 978-1-939824-00-4. (原始内容存档于2018-01-29).
- Sourceforge.net(页面存档备份,存于互联网档案馆) ,sed FAQ(2003年3月)
外部链接
教程
- Sed - An Introduction and Tutorial(页面存档备份,存于互联网档案馆), by Bruce Barnett
- SED -- A Non-interactive Text Editor (1974)(页面存档备份,存于互联网档案馆), by Lee E. McMahon
- 31+ Examples For Sed Linux Command In Text Manipulation(页面存档备份,存于互联网档案馆), by Mokhtar Ebrahim
- Sed教學(页面存档备份,存于互联网档案馆)
示例
- Major sources for sed scripts, files, usage
- Roger Chang's SED and Shell Scripts (2012)(页面存档备份,存于互联网档案馆)
- Top 'sed' commands – Usage examples
- Sed command examples in Unix & Linux(页面存档备份,存于互联网档案馆)
其他链接
- GNU sed主页(包括GNU sed手册)
- sed the Stream Editor(2004)(页面存档备份,存于互联网档案馆) (Eric Pement)
- sed-users Yahoo讨论组(页面存档备份,存于互联网档案馆)