Skip to content

古老的行编辑器:ed

本文将介绍行编辑器ed

什么是ed

edUnix系统最早的编辑器之一,是一个面向的文本编辑器,用于对文件进行增喊改查操作。后续熟知的viawksed 等都借鉴了ed 编辑器的设计,比如,vi 的底层是行编辑器exed 特征的扩展集)。

好在Gnu项目将其移植到了Linux 中,我们才得以在Linux 中使用它,地址为: https://www.gnu.org/software/ed/

当前文档使用的ed版本为: GNU ed 1.20

安装ed

目前最新的版本是1.20 版本

当前时间:2024年10月31日

下载ed

# wget https://ftp.gnu.org/gnu/ed/ed-1.20.tar.lz

解压

# lzip -d ed-1.20.tar.lz
# tar xf ed-1.20.tar

编译安装

# cd ed-1.20
# ./configure
# make
# make install

查看版本

# ed --version

若安装完成,会输出以下信息

GNU ed 1.20
Copyright (C) 1994 Andrew L. Moore.
Copyright (C) 2024 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

ed的基本使用

启动ed编辑器

使用ed filename,该命令会尝试打开filename 文件,若当该文件不存在时,则会报错filename: No such file or directoryed则会进入到编辑模式,直到手动保存,该文件才会被创建,并且写入内容。

文件存在:

# ed filename_1
12
q
#

当文件存在的时候,使用ed即可打开该文件,并且输出字符数,输入q退出。

文件不存在:

# ls -lhta filename_2
ls: cannot access filename_2: No such file or directory
#
# ed filename_2
filename_2: No such file or directory
a
hello filename_2
.
w
17
q
# cat filename_2
hello filename_2
#

当文件不存在的时候,使用ed 尝试打开该文件的时候,会报错No such file or directory ,但是还是会进入到编辑模式,此时若输入a命令,接着输入需要追加的行hello filename_2 ,输入. 进行结束输入,命令w 则进行保存,保存完成后,会输出字符数,最后输入q 进行退出ed 编辑器。

数据打印和遍历

进入ed 编辑器打开文件后,可以通过如下命令打印和定位行信息。

数据准备

# echo -e '123\n456\n789' >> filename_1
#
# cat filename_1
hello world
123
456
789
#

使用p 显示当前的行:

# ed filename_1
24
p
789

使用ed 默认打开文件后,会进入到最后一行。使用p 命令可以显示当前行。

使用,p 打印所有行:

# ed filename_1
24
,p
hello world
123
456
789

使用ed 默认打开文件后,使用,p 会打印所有行。

若想打印固定的行的话,可以使用{startN},{endN}p 命令,这才是,p 的完整写法,如,打印2到4行,则命令如下:

# ed filename_1
24
2,4p
123
456
789

使用= 打印当前文件的行号

# ed filename_1
24
=
4

除此之外,还能使用n 来打印所在行的行号和内容

# ed filename_1
24
n
4       789

若想输出固定行,和p 命令类似,如,打印2到4行的内容,包括行号,则命令如下:

# ed filename_1
24
2,4n
2       123
3       456
4       789

行定位

ed 打开文件后,默认会定位到最后一行,如下命令,可以快速进行行定位。

准备数据:

# echo -e "a\nb\nc\nd\ne\nf"  > filename_1

ed 中,输入1 可以定位到第一行,$ 则定位到最后一行。

# ed filename_1
12
1
a
$
f

不仅如此,还能基于当前行进行快速定位,比如定位到当前行的后2行。

# ed filename_1
12
1
a
+2
c

定位到当前行的前2行。

# ed filename_1
12
$
f
-2
d

追加文本

ed 中,有2个命令,分别是ai ,其含义如下:

  • a:在当前行后追加行
  • i :在当前行前插入行

使用a 进行追加行

# ed filename_1
24
a
a append to data
.
w
41
q
#

ed 中,使用a 命令后会进入到插入模式,可以输入多行的内容,输入完成后,输入. 进行结束输入,w 会保存内容到磁盘,q则退出ed 编辑器。

查看文件内容

# cat filename_1
hello world
123
456
789
a append to data
#

使用i 插入行

# ed filename_1
41
1
hello world
n
1       hello world
i
hello insert data
ooooooo
.
w
67
q
#

上述命令中,在ed 打开filename_1 后,使用1 先切到到第1行,并且使用n 输出当前行的行号和内容,随后输入i 指令,插入了2行内容,输入.进行结束输入,随后保存到磁盘,接着退出。

查看文件

# cat filename_1
hello insert data
ooooooo
hello world
123
456
789
a append to data
#

需要插入的内容,已经被插入到最前面了。

如果在追加内容中,恰好需要在单行输入. ,该. 将作为字符,而非结束标志符,应该在该. 后再追加一个空格,例如. ,实际操作如下:

# > filename_1
#
# ed filename_1
0
i
insert into data
. 
123456
.
w
27
q

请注意,在insert...123456 之间的. ,是. + 空格,否则会被当成是结束符。

使用cat -A 来查询一下:

# cat -A filename_1
insert into data$
. $
123456$
#

删除行

ed 中,使用d 可以进行删除行操作,首先进行数据准备:

# echo -e "a\nb\nc\nd\ne\nf"  > filename_1
# cat filename_1
a
b
c
d
e
f
#

使用d 可以删除当前行:

# ed filename_1
12
d
,p
a
b
c
d
e

进入ed 后,默认会定位到最后一行,使用d 指令,将删除最后一行,即f 被删除了。

不仅如此,还能指定行进行删除,比如2到4行进行删除:

# ed filename_1
10
2,4d
,p
a
e

进入ed 后,使用2,4d 指令,将删除2到4行,即bc 被删除了。

如果想删除全部行,则直接执行,d 即可删除所有行:

# ed filename_1
4
,d

文件的退出

使用q 指令会尝试退出ed 编辑器,当内存数据没有写入到磁盘的时候,会报错?

# ed filename_1
0
a
123
.
q
?

此时若想退出ed 编辑器,可以使用Q 指令进行强制退出,内存的数据将会丢弃,不会写入到磁盘中。

# cat filename_1
# ed filename_1
0
a
123
.
q
?
Q
# cat filename_1
#

若想保存后退出ed 编辑器,可以使用w 先进行写入到磁盘,而后使用q 进行退出。

# ed filename_1
0
a
123
.
w
4
q
# cat filename_1
123
#

ed的高级操作

数据准备

在开始之前,需要准备一份数据

# cat >> test.txt << EOF
name    age     sex
Alice   28      F
Bob     32      M
Charlie 25      M
Daisy   29      F
Ethan   30      M
Fiona   27      M
George  31      M
Hannah  26      F
Isaac   33      M
Julia   24      F
EOF
#

查看数据

# cat test.txt
name    age     sex
Alice   28      F
Bob     32      M
Charlie 25      M
Daisy   29      F
Ethan   30      M
Fiona   27      M
George  31      M
Hannah  26      F
Isaac   33      M
Julia   24      F
#

查看数据基本信息

# wc test.txt
 11  33 200 test.txt
#

其中test.txt 的信息为:

  • 11行
  • 33个单词
  • 200个字符

ed查询行数据

准备工作

使用ed 跟上文件名,即可打开文件。

该操作是将文件的内容放到内存缓冲区中,当编辑完成后,需要手动保存,此时才会将内存中的数据写入磁盘中。

# ed test.txt
200

默认使用ed 打开文件后,会输出文件字符数,并且将位置定位到最后一行。

简单查询

此时使用p 会打印当前行的内容,即最后一行。

# ed test.txt
200
p
Julia   24      F

若想查询所有的内容,可,p 即可。

,p
name    age     sex
Alice   28      F
Bob     32      M
Charlie 25      M
Daisy   29      F
Ethan   30      M
Fiona   27      M
George  31      M
Hannah  26      F
Isaac   33      M
Julia   24      F

复杂搜索

若想查询符合规范的行,比如sexM 的行。

g/M/p
Bob     32      M
Charlie 25      M
Ethan   30      M
Fiona   27      M
George  31      M
Isaac   33      M


其中g 表示全局、M 表示搜索关键字为Mp 是打印匹配行,每个指令由/ 分割开来,若不包含g 则默认只匹配一行。

/M/p
Bob     32      M


若想更为精确的匹配,如 1-8行中出现M的行信息。

1,8g/M/p
Bob     32      M
Charlie 25      M
Ethan   30      M
Fiona   27      M
George  31      M


利用正则表达式搜索

除此之外,ed 还支持正则表达式,比如查询namee 结尾的行信息。

g/.*e\s/p
name    age     sex
Alice   28      F
Charlie 25      M
George  31      M


其正则表达式.*e\s 的意思是匹配以e 紧接着空格的行。

ed 编辑行数据

数据准备

要编辑行内容,首先要先将文件加载到内存缓冲区中,即使用ed 打开文件。

# ed test.txt
200


进行简单的替换

现在将第一行的a 替换为A

1
name    age     sex
s/a/A/
1
nAme    age     sex


首先,需要切换到第一行,然后使用 s/a/A/ 将小写的 a 替换为大写的 A。不过,查看后发现该命令只修改了第一个出现的 a,而后续的 a 并未替换。

这是因为在默认情况下,ed 只会修改首次匹配到的内容。若想替换整行中的所有匹配项,需要在命令后添加参数 g,表示全局替换。

接下来,将第一行中的 e 替换为 E,并对所有匹配项进行替换。

1
nAme    age     sex
s/e/E/g
1
nAmE    agE     sEx


从上面的结果可以看出,替换已成功完成。

进行全局替换

如果想要将文本中所有的 e 替换为 E,则需要使用以下参数。

g/.*/s/e/E/g
,p
nAmE    agE     sEx
AlicE   28      F
Bob     32      M
CharliE 25      M
Daisy   29      F
Ethan   30      M
Fiona   27      M
GEorgE  31      M
Hannah  26      F
Isaac   33      M
Julia   24      F


g/.*/s/e/E/g 的含义如下:

  • 第一个 g:表示全局操作。
  • .*:表示匹配所有行。
  • s/e/E/:表示将 e 替换为 E
  • 最后一个 g:表示全局替换。

进行特定行区间数据替换

若只想修改特定行区间的内容,可以更改 .* 的参数值,例如:

,p
nAmE    agE     sEx
AlicE   28      F
Bob     32      M
CharliE 25      M
Daisy   29      F
Ethan   30      M
Fiona   27      M
GEorgE  31      M
Hannah  26      F
Isaac   33      M
Julia   24      F
2,$s/E/e/g
,p
nAmE    agE     sEx
Alice   28      F
Bob     32      M
Charlie 25      M
Daisy   29      F
ethan   30      M
Fiona   27      M
George  31      M
Hannah  26      F
Isaac   33      M
Julia   24      F


2,$s/E/e/g 的含义是:在第二行到最后一行的范围内匹配包含 E 的内容,并将其替换为 e

ed 中执行shell 命令

ed 中可以执行简单的命令,比如: 获取一下当前的服务器时间。

# ed
! date
Mon Nov  4 14:25:23 CST 2024
!

注意,ed 只能识别最简单的命令,如有特殊字符,比如date +"%F %T" 则不行,因为% 是特殊字符,用于引用文件和行,% 正确的用法为:

# ed filename_1
12
! ls %
 ls filename_1
filename_1
!

而如果直接使用date +"%F %T",会达不到预期效果:

# ed filename_1
12
! date +"%F %T"
 date +"filename_1F filename_1T"
filename_1F filename_1T
!

好在可以将该命令写入外部文件中,在ed 中进行调用即可:

首先,需要先准备好脚本

# echo 'date +"%F %T"' >> getDate.sh
# sh getDate.sh
2024-11-04 14:36:34
#

而后在ed 中调用该脚本即可

# ed
! sh getDate.sh
2024-11-04 14:37:30
!

不仅如此,ed 还支持将执行的结果插入到当前文本中,例如:

# ed
r ! sh getDate.sh
20
,p
2024-11-04 14:40:38


只需要r !加上执行的命令,即可将命令执行的结果插入到当前文本中。

ed 脚本化

可以将ed 的编辑命令放在独立的文件中,并且将他们作为ed行编辑器的输入,这样的话ed就具备了脚本化的能力。

例如: 将一些列的ed 语句放入到ed.script 的文件中,可以利用下面的命令,对文件执行该ed 脚本:

ed filename < ed.script

可以来尝试一下:

首先,来编写ed.script(可以任意命名该文件)

# cat ed.script
0,r ! date
$,a
the end.
ed url site: https://www.gnu.org/software/ed
.
g/.*/s/a/A/g
g/.*/s/c/C/g
w
q
#

解析一下每个语句的含义:

  • 0,r ! date :在首行插入date 命令执行的结果。
  • $,a :在尾行追加2行字符,第一行为:the end.,第二行为:ed url site: https://www.gnu.org/software/ed ,第三行的.a命令的结束符。
  • g/.*/s/a/A/g:进行全文全局替换,将a替换为A
  • g/.*/s/c/C/g:进行全文全局替换,将c替换为C
  • w:保存。
  • q:退出。

接着,使用ed filename < ed.script 的形式来执行该脚本。

首先,先查看filename_1 的内容。

# cat filename_1
a
b
c
d
e
f
#

接着,便对该文件执行ed.script 命令。

# ed filename_1 < ed.script
12
29
95
#

最后再次查看filename_1 文件。

# cat filename_1
Mon Nov  4 15:14:21 CST 2024
A
b
C
d
e
f
the end.
ed url site: https://www.gnu.org/softwAre/ed
#

总结

edUinx下的上古行编辑器,在目前的主流Linux版本中,都没有了它的身影,但是它影响了sedgrepvi 等一众软件,甚至于在上述软件使用中都能看到ed 的身影。

如果你正在学习sedgrepvi 等,不妨花几分钟了解一下ed 这个“老前辈”。




古老的行编辑器:ed

https://wangli2025.github.io/2024/11/04/The-oldest-line-editor-ed.html

本站均为原创文章,采用 CC BY-NC-ND 4.0 协议。转载请注明出处,不得用于商业用途。

Comments