The GNU ed line editor [译]

GNU ed 手册 (version 1.16, 2020-02-20).

原址:https://www.gnu.org/software/ed/manual/ed_manual.html

  • 概览: ed 概览
  • 行编辑简介: GNU ed 起步
  • 调用 ed: 命令行界面
  • 行寻址: 在缓冲区中指定行/范围
  • 正则表达式: 文本选择模式
  • 命令: GNU ed 识别命令
  • 限制: GNU ed 的固有局限性
  • 诊断: GNU ed 错误处理
  • 问题: 报告 bugs
  • GNU Free Documentation License: How you can copy and share this manual

Copyright © 1993, 1994, 2006-2020 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

1 概览

GNU ed 是一种基于行的文本编辑器。它以交互方式或通过 Shell 脚本对文本文件进行:创建、显示、修改等操作。ed 的受限版本(red)只能编辑当前目录中的文件且无法执行 Shell 命令。ed 是 Unix 中广泛使用的原始编辑器,因此某种意义上可以说:ed 是事实上的"标准"。但是,在大多数情况下,它已被 GNU Emacs 或 GNU Moe 等全屏编辑器取代。

GNU ed 基于 Brian W. Kernighan 和 P. J. Plauger 在1981年 Addison-Wesley 的著作"Software Tools in Pascal"中描述的编辑器算法。

如果在调用 ed 时附加 file 参数,则会将对应文件的副本读入编辑器的缓冲区。对副本进行更改,不影响文件本身。退出时,所有未用'w'命令"明确保存"的变更将被丢弃。

ed 有两种不同的模式:command 命令模式和 input 输入模式。刚启动时,ed 处于命令模式。在这种模式下,从标准输入读取命令,并执行命令以操作编辑器缓冲区的内容。典型的命令可能如下所示:

1,s/old/new/g

new 替换字符串 old所有出现。

当输入诸如:'a'追加,'i'插入,'c'修改等命令时,就进入输入模式。这是将文本添加到文件的主要方法。在这种模式下,命令将不可用。此时的标准输入直接写入编辑器缓冲区。一个行由结尾的<换行符>字符表示。输入模式可通过在整行中输入一个单独的句点'.'结束。

所有 ed 命令都应用于整行或行的范围。例如:'d'删除行;'m'移动行……等等。如上例所示,可以通过替换命令仅修改行的一部分内容。但是,'s'命令依然是整行上执行的。

一般的,ed 命令有如下组成部分:零个或多个行地址,后跟单个字符命令和可能的附加参数;即,命令结构为: $$ [address[,address]]command[parameters] $$ 地址标识出行或行的范围。如果给出的地址少于命令接受的地址,则使用默认地址。

2 行编辑简介

ed 的作者是 Ken Thompson 和 Dennis Ritchie,该工具伴随 Unix 操作系统一起创建。Thompson 和 Ritchie 已经在其中添加了模式匹配功能(请参阅正则表达式),这是对其前身——更复杂、可编程的 QED 的改进。

就本教程而言,建议具备 Unix Shell 和 sh 的基本知识,因为 ed 与他们紧密关联。(有关 bash 的详细信息,请参见 bash 手册)。

行编辑器和全屏编辑器的主要区别在于:全屏编辑器可对用户命令做出即时反馈,而行编辑器有时要在输入上花较长时间才能看到效果。显然,即时反馈的优势在于,如果犯了错,可以在产生更严重的破坏之前及时纠正。在 ed 中编辑则需要更多的策略和前瞻性;但是一旦熟练掌握了其应用,效率收益颇高。

许多 ed 命令语法与其他 Unix 实用程序也通用。

与 Shell 程序一样,<RETURN>(回车键)输入一行。因此,当我们在 ed 中说"输入"命令或某些文本时,暗示<RETURN>在每一行的末尾。在键入<RETURN>之前,可以通过键入<BACKSPACE>来向后擦除字符,或者键入<CONTROL>-u(即,按住CONTROL 键并键入 u)以擦除整行来对行进行校正。

刚打开 ed 的时候,它会等待我们的指令,但不像 Shell 那样有提示符。因此,我们从让 ed 显示提示符开始,使用<P>提示符)命令:

1$ ed 
2P 
3*

默认情况下,ed 使用星号*作为命令提示符,以避免与 Shell 命令提示符$混淆。

我们可以通过!前缀来运行 Unix Shell 内部的命令(!感叹号,又名 "bang")。例如:

1*!date
2Mon Jun 26 10:08:41 PDT 2006
3!
4*!for s in hello world; do echo $s; done
5hello
6world
7!
8*

到目前为止,这与在 Unix Shell 中运行命令没有什么不同。现在,假设我们要编辑命令的输出或将其保存到文件中。首先,我们必须将命令输出捕获到一个称为缓冲区的临时位置,以便 ed 可以访问。执行 ed<r>命令(助记符:read):

1*r !cal -m
2137
3*

这里 ed 告诉我们它将 137 个字符读入编辑器缓冲区,即:cal 命令的输出,该命令打印一个简单的 ASCII 日历。要显示缓冲区内容,我们发出<p>(print)命令(不要与大写的<P>提示命令混淆!)。为了指示应打印的缓冲区行范围,我们在命令前加上单独的,(逗号),这是“整个缓冲区”的简写:

 1*,p
 2      June 2006
 3Mo Tu We Th Fr Sa Su
 4          1  2  3  4
 5 5  6  7  8  9 10 11
 612 13 14 15 16 17 18
 719 20 21 22 23 24 25
 826 27 28 29 30
 9
10*

现在,让我们将缓冲区内容写入名为 junk 的文件,使用<w>(write)命令:

1*w junk
2137 
3*

毋须多言,时常将缓冲区内容写入文件是一个好习惯,因为当我们退出时,对缓冲区的未保存变更将丢失。

下面的示例演示了 ed 行编辑的一些基本概念。我们首先创建一个文件 sonnet,引用莎士比亚的十四行诗。与 Shell 一样,所有输入必须后跟一个<newline>字符。命令模式中以 # 开头的命令作为注释,将被忽略。输入模式中 # 开头的行是正文。

 1$ ed
 2# The 'a' command is for appending text to the editor buffer.
 3a
 4No more be grieved at that which thou hast done.
 5Roses have thorns, and filvers foutians mud.
 6Clouds and eclipses stain both moon and sun,
 7And loathsome canker lives in sweetest bud.
 8.
 9# Entering a single period on a line returns ed to command mode.
10# Now write the buffer to the file 'sonnet' and quit:
11w sonnet
12183
13# ed reports the number of characters written.
14q
15$ ls -l
16total 2
17-rw-rw-r--    1 alm           183 Nov 10 01:16 sonnet
18$

在下一个示例中,我们修正文件中的一些拼写错误。

 1$ ed sonnet
 2183
 3# Begin by printing the buffer to the terminal with the 'p' command.
 4# The ',' means "all lines".
 5,p
 6No more be grieved at that which thou hast done.
 7Roses have thorns, and filvers foutians mud.
 8Clouds and eclipses stain both moon and sun,
 9And loathsome canker lives in sweetest bud.
10# Select line 2 for editing.
112
12Roses have thorns, and filvers foutians mud.
13# Use the substitute command, 's', to replace 'filvers' with 'silver',
14# and print the result.
15s/filvers/silver/p
16Roses have thorns, and silver foutians mud.
17# And correct the spelling of 'fountains'.
18s/utia/untai/p
19Roses have thorns, and silver fountains mud.
20w sonnet
21183
22q
23$

ed 是基于行的,我们必须告诉它要编辑哪一行或某些范围的行。在上面的示例中,通过指定行号或缓冲区中的序列来执行此操作。另外,我们也可以指定行中的唯一的字符串,例如'/filvers/',其中/界定了要查找的字符串。随后的命令仅影响选定的行,或者说:当前行。查找到匹配后,替换命令将该行的匹配部分进行替换,语法为's/old/new/'

虽然 ed 每行仅接受一个命令,打印命令'p'是一个例外,可以附加到大多数命令的末尾。

在下一个示例中,我们把标题添加到文件中

 1$ ed sonnet
 2183
 3a
 4Sonnet #50
 5.
 6,p
 7No more be grieved at that which thou hast done.
 8Roses have thorns, and silver fountains mud.
 9Clouds and eclipses stain both moon and sun,
10And loathsome canker lives in sweetest bud.
11Sonnet #50
12# The title got appended to the end; we should have used '0a'
13# to append "before the first line".
14# Move the title to its proper place.
155m0p
16Sonnet #50
17# The title is now the first line, and the current address has been
18# set to the address of this line as well.
19,p
20Sonnet #50
21No more be grieved at that which thou hast done.
22Roses have thorns, and silver fountains mud.
23Clouds and eclipses stain both moon and sun,
24And loathsome canker lives in sweetest bud.
25wq sonnet
26195
27$

当用 ed 打开一个文件时,当前地址最初设置为该文件最后一行的地址。类似的,移动命令'm'将当前地址设置为最后移动的行的目的地址。

相关程序或例程是 vi(1), sed(1), regex(3), sh(1)。相关文件有:

  • Unix User's Manual Supplementary Documents:12-13
  • BW Kernighan 和 PJ Plauger:"Software Tools in Pascal",Addison-Wesley,1981

3 调用 ed

启动 ed 的命令格式为:

1ed [options] [file]
2# or
3red [options] [file]

file 指明被读取的文件的名字。如果文件名以!开头,将被解释为 Shell 命令。这种情况下 ed 读取的是sh执行 file 的输出结果。要读取文件名以!开头的文件的内容,需要在!前加上\转义。默认的文件名被设置为 file,除非前缀是!

ed 支持如下选项:

-h

--help Print an informative help message describing the options and exit.

-V
--version

Print the version number of ed on the standard output and exit. This version number should be included in all bug reports.

-G
--traditional

Forces backwards compatibility. This affects the behavior of the ed commands 'G', 'V', 'f', 'l', 'm', 't' and '!!'. If the default behavior of these commands does not seem familiar, then try invoking ed with this switch.

-l
--loose-exit-status

Don't exit with bad status if a command happens to "fail" (for example if a substitution command finds nothing to replace). This can be useful when ed is invoked as the editor for crontab.

-p string
--prompt=string

Specifies a command prompt string and turns prompting on. Showing the prompt string may be toggled on and off with the 'P' command.

-r
--restricted

Run in restricted mode. This mode disables editing of files out of the current directory and execution of shell commands.

-s
--quiet
--silent

Suppresses diagnostics, the printing of byte counts by 'e', 'E', 'r' and 'w' commands, and the '!' prompt after a '!' command. This option may be useful if ed's standard input is from a script.

-v
--verbose

Verbose mode; prints error explanations. This may be toggled on and off with the 'H' command. Exit status: 0 if no errors occurred; otherwise >0.

4 行寻址

地址表示某行在缓冲区中的行号。ed 维护着一个当前地址,当没有明确指定地址时,该地址作为默认地址提供给命令。文件读取完毕,当前地址被设置为该文件的最后一行。一般情况下,当前地址总是被设置为一个命令所影响的最后一行的地址。

一个特例是行号为 0 的行。意为"缓冲区的开头",在任何有意义的地方都有效。

地址范围由两个地址组成,其间用(,)或(;)分隔。在(;)分隔的范围中,第二个地址被计算前,当前地址(.)被设为第一个地址;当第二个地址包含正则表达式时,这个特性可被用来设置搜索的开始行。第一个地址的值不能超过第二个地址。

分隔符两边的地址都可以被省略。

  • 若只提供第一个地址,则第二个地址与第一个地址相同。

  • 如果只提供第二个地址,则

    • 以(,)分隔的范围是:1,addr;
    • 而由(;)分隔的范围是:.,addr

如果给出 n 个元组的地址,其中 n > 2,则相应的范围由 n 个元组中的最后两个地址确定(1,2,3,4,5)。如果只需要一个地址,则使用最后一个地址。将任意数量的地址分配给需要零个地址的命令将引发错误。

行地址的构造如下:

.

The current line (address) in the buffer.

$

The last line in the buffer.

n

The nth line in the buffer, where n is a number in the range '0,$'.

+n

The nth next line, where n is a non-negative number.

-n

The nth previous line, where n is a non-negative number.

+

The next line. This is equivalent to '+1' and may be repeated with cumulative effect.

-

The previous line. This is equivalent to '-1' and may be repeated with cumulative effect.

,

The first through last lines in the buffer. This is equivalent to the address range '1,$'.

;

The current through last lines in the buffer. This is equivalent to the address range '.;$'.

/re/

The next line containing the regular expression re. The search wraps to the beginning of the buffer and continues down to the current line, if necessary.

?re?

The previous line containing the regular expression re. The search wraps to the end of the buffer and continues up to the current line, if necessary.

'x

The apostrophe-x character pair addresses the line previously marked by a 'k' (mark) command, where 'x' is a lower case letter from the portable character set '[a-z]'.

5 正则表达式

正则表达式是用于选择文本的模式。例如:

1g/string/

打印所有包含 string 的行。正则表达式也可以用在's'替换命令中的匹配文本部分。

除了字符串字面量外,正则表达式还可以表示字符类,表示"由相应的正则表达式匹配"的字符串。如果正则表达式可以匹配一行中的多个字符串,则最左边的匹配项就是被选则的匹配项。如果正则表达式允许可变数量的匹配字符,则匹配从该位置开始的最长序列。

一个空的正则表达式(//)等价于上一个匹配的表达式。

以下符号用来构造正则表达式:

 1c
 2Any character c not listed below, including '{', '}', '(', ')', '<' and '>', matches itself.
 3
 4\c
 5Any backslash-escaped character c, other than '{', '}', '(', ')', '<', '>', 'b', 'B', 'w', 'W', '+' and '?', matches itself.
 6
 7.
 8Matches any single character.
 9
10[char-class]
11Matches any single character in char-class. 
12To include a ']' in char-class, it must be the first character. 
13A range of characters may be specified by separating the end characters of the range with a '-', 
14e.g., 'a-z' specifies the lower case characters. 
15The following literal expressions can also be used in char-class to specify sets of characters:
16          [:alnum:] [:cntrl:] [:lower:] [:space:]
17          [:alpha:] [:digit:] [:print:] [:upper:]
18          [:blank:] [:graph:] [:punct:] [:xdigit:]
19If '-' appears as the first or last character of char-class, then it matches itself. 
20All other characters in char-class match themselves.
21
22Patterns in char-class of the form:
23          [.col-elm.]
24          [=col-elm=]
25where col-elm is a collating element are interpreted according to 'locale (5)'. 
26See 'regex (7)' for an explanation of these constructs.
27
28[^char-class]
29Matches any single character, other than newline, not in char-class. char-class is defined as above.
30
31^
32If '^' is the first character of a regular expression, then it anchors the regular expression to the beginning of a line. 
33Otherwise, it matches itself.
34
35$
36If '$' is the last character of a regular expression, it anchors the regular expression to the end of a line. 
37Otherwise, it matches itself.
38
39\(re\)
40Defines a (possibly null) subexpression re. Subexpressions may be nested. 
41A subsequent backreference of the form '\n', where n is a number in the range [1,9], 
42expands to the text matched by the nth subexpression. 
43For example, the regular expression '\(a.c\)\1' matches the string 'abcabc', 
44but not 'abcadc'. Subexpressions are ordered relative to their left delimiter.
45
46*
47Matches zero or more repetitions of the regular expression immediately preceding it. 
48The regular expression can be either a single character regular expression or a subexpression. 
49If '*' is the first character of a regular expression or subexpression, then it matches itself. 
50The '*' operator sometimes yields unexpected results. 
51For example, the regular expression 'b*' matches the beginning of the string 'abbb', 
52as opposed to the substring 'bbb', since a null match is the only left-most match.
53
54\{n,m\}
55\{n,\}
56\{n\}
57Matches the single character regular expression or subexpression immediately preceding it at least n and at most m times. 
58If m is omitted, then it matches at least n times. 
59If the comma is also omitted, then it matches exactly n times. 
60If any of these forms occurs first in a regular expression or subexpression, 
61then it is interpreted literally (i.e., the regular expression '\{2\}' matches the string '{2}', and so on).
62
63\<
64\>
65Anchors the single character regular expression or subexpression immediately following it 
66to the beginning (in the case of '\<') or ending (in the case of '\>') of a word, 
67i.e., in ASCII, a maximal string of alphanumeric characters, including the underscore (_).
68The following extended regular expression operators are preceded by a backslash '\' 
69to distinguish them from traditional ed syntax. 
70They may be unavailable depending on the particular regex implementation in your system.
71
72\`
73\'
74Unconditionally matches the beginning '\`' or ending '\'' of a line.
75
76\?
77Optionally matches the single character regular expression or subexpression immediately preceding it. 
78For example, the regular expression 'a[bd]\?c' matches the strings 'abc', 'adc' and 'ac'. 
79If '\?' occurs at the beginning of a regular expressions or subexpression, then it matches a literal '?'.
80
81\+
82Matches the single character regular expression or subexpression immediately preceding it one or more times. 
83So the regular expression 'a\+' is shorthand for 'aa*'. If '\+' occurs at the beginning of 
84a regular expression or subexpression, then it matches a literal '+'.
85
86\b
87Matches the beginning or ending (null string) of a word. 
88Thus the regular expression '\bhello\b' is equivalent to '\<hello\>'. 
89However, '\b\b' is a valid regular expression whereas '\<\>' is not.
90
91\B
92Matches (a null string) inside a word.
93
94\w
95Matches any character in a word.
96
97\W
98Matches any character not in a word.

6 命令

所有的 ed 命令都是单个字符。当然,某些命令需要额外的参数。如果命令的参数跨越多行,则除最后一行外,每行都必须以反斜杠\结尾 。

通常,每行最多允许一个命令。但是,大多数命令都接受打印后缀,即'p'(打印),'l'(列表)或'n'(枚举),以打印受命令影响的最后一行。提供多个打印后缀并不轻便,但是 ed 允许非重复打印后缀的任意组合,并结合其效果。如果给出了任何打印后缀,则必须紧随命令之后。

'e', 'E', 'f', 'r''w' 这些命令接收可选的 file 参数,参数与命令之间用一个或多个空格分隔。

中断(一般为<Control-C>)可以中止当前命令并使编辑器返回命令模式。

ed 识别以下命令:默认地址与命令放在一起显示,若未指定地址则在括号中给出地址范围。

(.)a

在地址标明的行之后将文本追加到缓冲区。地址 0(零) 对该命令有效——它将输入的文本放在缓冲区的开头。命令之后进入输入模式以输入文字。当前地址设置为最后输入的行的地址,否则,设置为地址标明的行。

(.,.)c

改变缓冲区中的行。地址标明的一或多行从缓冲区中被删除,命令后进入输入模式。新输入的文本在所有被删除的行所在的位置插入。当前地址设置为最后输入的行的地址,否则,设置为删除对应行后的地址。如果被删除的行原本就在缓冲区末尾,当前地址被设置为新的最后一行;如果缓冲区中已经没有行,则当前地址被设置为 0。被删除的行被复制到剪切缓冲区。

(.,.)d

从缓冲区中删除地址标识的行。当前地址被设置为删除对应行后的地址;如果被删除的行原本就在缓冲区末尾,当前地址被设置为新的最后一行;如果缓冲区中已经没有行,则当前地址被设置为 0。被删除的行被复制到剪切缓冲区。

e file

编辑指定文件,并设置默认文件名。若 file 未指定,则使用默认文件名。缓冲区中的所有行在新文件读取之前被删除。当前地址被设置为缓冲区中的最后一行。

如果 file!为前缀,则被解释为 Shell 命令,并将该命令的输出读入到缓冲区。这种情况下默认文件名无变化。

若自上次执行'w'命令将缓冲区内容写到文件之后,缓冲区中有任何改变,则该命令打印一个警告。

E file

无条件的打开另一个文件。与'e'命令类似,但是丢弃未保存的改变而无任何警告。

f file

设置默认文件名为:file。如果未指定 file,则打印未转义的默认文件名。

(1,$)g/re/command-list

全局命令。分两步实施。首先,与re匹配的所有行被标记。然后,从头至尾遍历文件,命令列表里的每个命令都会逐个实施到每个标记的行上,当前地址也随着逐行遍历而改变。实施过命令的行被取消标记。当前地址的最终值,被设置为命令列表中最后一条命令影响的最后一行。如果没有匹配的行,当前地址不变。

命令列表的第一个命令必须于'g'在同一行。其他命令必须各自占一行。多行命令中除了最后一行,其他行必须以反斜杠\结尾。除了'g','G','v','V',其他命令都可以出现在命令列表中。'.'字符结束'a','c','i'命令的输入模式,如果'.'在最后一行则可以被省略。默认情况下,命令列表中的单独<newline>等价于'p'命令。如果 ed 启动时带了-G参数,则命令列表中的<newline>等价于'.+1p'

(1,$)G/re/

交互式全局命令。交互式的编辑与re匹配的行。首先打印匹配的行,当前地址设置为该行,然后提示用户输入命令列表。当前地址的最终值为最后一条命令影响的行。如果没有匹配的行,当前地址不变。

命令列表的格式与'g'命令相同。单独的<newline>相当于不执行任何命令。单独的'&'表示重复上一个非空的命令。

h

帮助。打印上一个错误的解释。

H

错误解释的开关。默认情况下,不打印。建议在执行 ed 脚本之前开启以便调试。

(.)i

在地址标识的行之前插入文本。地址 0 对此命令有效,这将导致文本被插入到缓冲区的开头。命令后进入输入模式。当前地址设置为最后输入的行的地址,否则,设置为地址标识的行。

(.,.+1)j

合并地址标识的行,用单一行替换所有被合并的行。如果只给出了一个地址,命令什么也不做。如果有若干行被合并,则被替换的所有行都被复制到剪切缓冲区,且当前地址被设置为合并后的行。否则,当前地址不变。

(.)kx

用小写字母x标记一行。被标记的行可以由对应的小写字母寻址(比如'x)。除非该行被删除或修改,否则标记不会消失。当前地址无变化。

(.,.)l

列表。直白的打印地址标识的行。每行的结尾由$标记,而行内的所有$字符都会添加前导的反斜杠\。特殊字符按照转义序列打印。当前地址被设置为最后打印的行。

(.,.)m(.)

移动缓冲区中的行。地址标识的行被移动到'm'命令右边指定的行的后面。地址 0 对此命令有效,意为将行移动到缓冲区开头。如果目标地址包含在寻址行范围内则报错。当前地址被设置为被移动的最后一行的新地址。

(.,.)n

行号命令。打印地址标识的行,行号作为前导且用<tab>与行文本隔开。当前地址设置为最后被打印的行。

(.,.)p

打印地址标识的行。当前地址设置为最后被打印的行。

P

命令提示符开关。除非通过启动时的'-p'参数指定提示符字符串,否则默认情况下不显示提示符。提示符默认字符为:星号('*')

q

退出 ed。若自上次执行'w'命令保存缓冲区到文件后,缓冲区中有任何改变则会打印警告信息。

Q

无条件退出 ed。与'q'类似,但缓冲区中未保存的改变将丢失而不会提出警告。

($)r file

读取指定文件的内容,追加到地址标识的行后面。如果 file 未指定,则使用默认文件名。如果执行命令前没有默认文件名,则使用 file 作为默认名。否则,默认文件名无变化。地址 0 对此命令有效。意为将读取到的内容放置在缓冲区开头。当前地址被设置为最后读取的行,否则设置为地址标识的行。

如果 file!为前缀,则被解释为 Shell 命令,读取的是脚本执行后的输出。这种情况加默认文件名无变化。

(.,.)s/re/replacement/

替换命令。地址标识范围内与re匹配的部分将被replacment替换。默认情况下,只有第一个匹配被替换。's'命令可以与后缀'g',count,'l'以及'p'组合。如果使用了'g'后缀,则所有匹配都会被替换。count后缀(其中:count > 0),表示只替换 count 个匹配。'g'count不能同时使用。'l','n''p'是常见的打印后缀。如果地址标识的行内没有任何替换操作则会报错。当前地址被设置为最后一个出现匹配的行。如果一行被拆分,则看做是每个新行上都发生了替换。若未发生替换,则当前地址不变。最后被修改的一行将被复制到剪切缓冲区。

rereplacement可以由除了<space><newline>之外的任何字符界定,'s'命令格式使用的字符详见下文。如果尾部的界定符被省略,则相当于在最后一个受影响的行上执行'p'命令。如果's'命令是'g''v'命令列表的一部分并且不是最后一条命令时,结尾的界定符不能被省略,这是为了避免跟随后的转义新行混淆。

replacement中未转义的'&'代表当前匹配的文本。字符序列\m(其中 m 的区间[1,9]),被替换为第 m 个后向引用表达式。如果对应的后向引用不存在,\m会被替换成空字符串。如果replacement只包含单独的'%',则表示上一个替换命令使用的replacement

replacement中,一行可以拆分成多行,新拆分的行需要用\转义。这些在replacement中的\将移除其后字符的特殊含义。

(.,.)s

重复上一个替换命令。这个格式的's'命令接受'g'count作为后缀,还包括'p''r'后缀。

'g'后缀切换上一个替换命令的全局开关,并且重置count的为 1。

'p'后缀则切换上一个替换命令的打印开关。

'r'后缀导致命令在上一次查找的结果上运行,而不是在替换过的结果上运行(如果是在替换后再查找)。

(.,.)t(.)

将地址标识的行复制到命令右边地址标识的行之后。如果目标地址为 0,则意为复制到缓冲区开头。当前地址设置为复制出的最后一行。

u

撤销上一条命令的效果,恢复当前地址为执行命令前的地址。

全局命令'g','G','v''V'对于 undo 作为单条命令看待。

'u'命令与自己互逆,它只能撤销最后一条命令。

(1,$)v/re/command-list

'g'类似,但是作用于地址范围内不匹配re的行。

(1,$)V/re/

'G'类似,但是当遇到地址范围内不匹配re的行会交互式的编辑。

(1,$)w file

将地址标记的行写入文件。目标文件的内容将被覆盖。若未设置默认文件名,则使用目标文件名作为默认名,否则文件名无变化。如果未指定目标文件名,则使用默认文件名。当前地址无变化。

如果文件名以!为前导,将被解释为 Shell 命令,并且地址标记的行将做为该 Shell 命令的标准输入,这种情况下默认文件名无变化。若试图通过'e''q'命令覆盖或丢弃缓冲器内容,缓冲区内容作为 Shell 命令的输入依然会得到警告。

(1,$)wq file

将地址标记的行写入文件,然后退出。

(1,$)W file

追加地址标记的行到文件结尾。与'w'命令类似,除了不会覆盖目标文件的内容。当前地址不变。

(.)x

将剪切缓冲区中的内容放置到地址标记行的后面。当前行被设置为最后拷贝的行。

(.,.)y

拷贝地址标明的行到剪切缓冲区。能覆盖剪切缓冲区命令有:'c','d','j','s','y'。当前地址不变。

(.+1)zn

滚动。从地址标记的行开始,一次打印 n 行,并设置窗口大小为 n。若未指定 n,则使用当前窗口大小。窗口的默认大小为屏幕尺寸减去 2 行,若屏幕尺寸无法确定则为 22 行。当前地址设置为最后被打印的行。

!command

执行 Shell 命令。通过sh(1)执行命令。!!表示与上一条相同的命令。ed 并不识别反斜杠\转义。但是%将被替换为默认的文件名。当从执行的命令中返回时,将在单独一行打印一个!。当前行的地址不变。

(.,.)#

注释。# 到换行符之间的内容都将被忽略。如果地址由;分隔,则当前地址被设置成;前的地址,否则,当前地址不变。

($)=

打印地址所标记的行号。不改变当前行地址。

(.+1)<newline>

空命令。单独打印地址标记的行。单一的<newline>等价于+1p。当前地址设置为被打印的行。

7 限制

如果终端挂起,ed 将试图将缓冲区写入 ed.hup 文件,失败则写入 $HOME/ed.hup。

edfile 参数中,任何前导反斜杠\将被解释为字面的意思。比如:ed 'hello\tworld'将编辑名为:'hellotworld'的文件。

如果文本文件不以<newline>字符结尾,ed 将在读写时追加该字符。在二进制文件中,则不然。一个二进制文件至少要包含一个 ASCII NUL 字符。如果最后一行被修改了,则在写入之前读取空文件(如:/dev/null)可防止将换行符附加到二进制文件中。

为了跟踪缓冲区中的文本行,ed 使用包含行的位置和尺寸的结构体的双向链表。每行的开销为:2个'pointers',1个'long int',1个'int'

8 诊断

如果 ed 的输入是普通文件或 HEREDOC,则出错就直接退出。其他情况下的错误,ed 只是打印一个问号?后返回命令模式。最后一个错误的解释可以通过'h'(help)命令查看。

如果'u'(undo)出现在全局命令列表中,则命令列表只执行一次。

首次试图在一个修改过的缓冲区上执行退出命令或编辑另一个文件将报错;再次执行相同命令会成功,但缓冲区中的变更会丢失。

9 报告 bugs

ed 中可能有 bug。手册中也会有错误或遗漏。如果你报告了,则都会被修正。否则这些错误将永远被遗留在程序中。

如果你发现了 ed 中的 bug,请发送电子邮件到:bug-ed@gnu.org。并注明详细的版本号,这可以通过ed --version查看。


说明

  1. 命令字符的书写并不统一,比如:<p>'p'都表示打印命令
comments powered by Disqus