古老的行编辑器:ed
本文将介绍行编辑器ed。
什么是ed
ed 是Unix系统最早的行编辑器之一,是一个面向行的文本编辑器,用于对文件进行增喊改查操作。后续熟知的vi 、awk 、sed 等都借鉴了ed 编辑器的设计,比如,vi 的底层是行编辑器ex (ed 特征的扩展集)。
好在Gnu项目将其移植到了Linux 中,我们才得以在Linux 中使用它,地址为: 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 directory,ed则会进入到编辑模式,直到手动保存,该文件才会被创建,并且写入内容。
文件存在:
# 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个命令,分别是a 和i ,其含义如下:
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行,即b 、c 被删除了。
如果想删除全部行,则直接执行,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
复杂搜索
若想查询符合规范的行,比如sex 是M 的行。
g/M/p
Bob 32 M
Charlie 25 M
Ethan 30 M
Fiona 27 M
George 31 M
Isaac 33 M
其中g 表示全局、M 表示搜索关键字为M,p 是打印匹配行,每个指令由/ 分割开来,若不包含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 还支持正则表达式,比如查询name 以e 结尾的行信息。
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
#
总结
ed 是Uinx下的上古行编辑器,在目前的主流Linux版本中,都没有了它的身影,但是它影响了sed 、grep、vi 等一众软件,甚至于在上述软件使用中都能看到ed 的身影。
如果你正在学习sed、grep、vi 等,不妨花几分钟了解一下ed 这个“老前辈”。