一旦开始进行替换和删除,能够撤销改变就变得十分重要。
例如,将单词“advertisement”的所有匹配项都改变为“ad”,决定输入:
:%s/advertisement/ad/g
但是,不小心键入错误,忘记了键入第二个“d”:
:%s/advertisement/a/g
这样就将所有的“advertisement”都替换为字母“a”。但是,不能通过将所有的“a”改变为“ad”来解决这个问题,因为字母“a”到处都是。当然,可以使用:q!命令,不保存工作就退出vi(如果处理的是一个已有文件的话),但是这样就丢失自上次保存以后所有的改变,前面的工作都白白浪费。那么,还有没有其他的方法?
希望删除10行,但键入的不是10dd,而是100dd,结果删除了100行。有没有方法将这100行恢复呢?
两个问题的答案是肯定的。vi中有两条命令可以用来撤销改变,另外还有一条重复上一次改变的命令:
u 撤销上一次命令对编辑缓冲区的修改,多次使用u键可以撤销前面多条命令,每次一条。
U 恢复最后一次修改的行,也可以撤销自己。
. 重复上一命令对编辑缓冲区的修改
u(小写字母“u”)命令撤销上一命令对编辑缓冲区所做的改变:插入、替换、改变或删除。
u命令可以撤销大量的改变,一次可以撤销一次修改,多次可以撤销前面多次修改,每次撤销一条。
U(大写字母“U”)命令将撤销自移动到当前行的那一刻起,对最后一次修改的行所进行的所有改变。
假设希望在编辑缓冲区的几个位置插入名称“Mxyzptlk”。这是一个比较难拼写的名称,而且每次插入都重新键入也很烦人,一个巧妙的方法是:将光标移到到希望插入的位置上,然间键入:
Mxyzptlk<ESC>
已经将这一名称插入到编辑缓冲区。现在,将光标移到到下一个希望插入的位置上去,并键入:
.
这将完成相同的插入。
使用.命令时需要小心,一旦进行了另一个改变,即便只是一个字符的删除,.命令的结果也将会随之改变。
注意:vi和vim在此处的处理有一些不同,使用时需关注自己的编辑环境。
vi中共有9个这样的缓冲区,编号从1至9。在任何时候,都可以将一个编号缓冲区中的内容插入到编辑缓冲区中。这样做时,需要键入一个”(双引号),后面跟着缓冲区的编号,再后跟一个p或者P(put,放入)(提醒:当处理行时,p命令在当前行的下面插入,P命令在当前行的上面插入)。
例如,为了将编号缓冲区#1的内容插入到当前行的下面,可以使用:
“1p
为了将编号缓冲区#1的内容插入到当前行的上面,可以使用:
“2P
通过这种方式,可以恢复并插入之前9次删除的内容。
例如,假设已经进行了若干次删除,而希望恢复其中一次的删除。但却忘记了是哪一次了。
首先键入”1p,如果所恢复的文本不是所需的,则可以键入u撤销插入,并尝试”2p。如果这一次未得到所需的文本,可以继续键入u撤销这次插入,再尝试”3p。一旦这样往下试,直到找到自己希望的内容。命令序列看上去是:
“1pu”2pu”3pu…
vim更加强大,在撤销了第一次插入之后,如果使用.(点号)命令重复插入,那么vi将自动地将缓冲区编号加1。可以使用:
“1pu.u.u…
提醒:编号缓冲区只存储删除的行,而不是行的一部分或者单个字符。
为了从现有的文件向编辑缓冲区中读入数据,可以使用:r命令。语法为:
:[line]r file
其中line是行号,file是文件的名称。
:r命令读取文件的内容,并将该内容插入到编辑缓冲区中的指定行之后。
使用行0(零)可以表示编辑缓冲区的开头。
使用$可以表示编辑缓冲区的末尾。
如果省略行号,那么vi将把新数据插入到当前行之后。这可能是最有用的:r命令形式。
vi中有几种调用常规shell命令的方法,而且在调用时不用停止vi。
第一种,可以通过键入:!,后面跟希望运行的命令来输入命令。这将告诉vi将命令发送给shell执行。当命令结束后,控制将返回给vi。
例如,为了显示时间和日期,可以输入:
:!date
命令效果如下:
2011年 09月 05日 星期一 22:08:13 CST
命令结束后可以看到一个消息。该消息根据vi版本的不同而有所不同。下面是几种常见的信息:
请按 ENTER 或其它命令继续
Press ENTER or type command to continue
Press any key to continue
[Hit return to continue]
此时只需要按下<Return>键就可以返回到vi中。
第二种,为了重复执行最近一条shell命令,不管上次输入命令以来过了多久,都可以使用下述命令完成该任务:
:!!
第三种,为了在编辑缓冲区中直接输入shell命令的输出,可以使用:r!命令,将shell命令的输出插入到当前行之后。(见上一节:将文件中的数据插入到编辑缓冲区中)
第四种,有时候可能希望输入不止一条shell命令。这时可以启动一个新的shell。这有两种方法:
1是使用:sh命令:
:sh
这将暂停vi,并启动一个新的默认shell副本。然后,您就可以根据需要输入任意数量的命令。当使用完这个shell之后,可以按^D键或输入exit命令停止这个shell。这样将又返回到vi中。
2可以通过运行一条实际命令来启动一个新shell。例如,为了启动一个新的Bash shell,可以运行bash程序:
:!bash
为了启动一个新的Tcsh shell,可以使用:
:!tcsh
和:sh命令一样,当结束shell时系统将返回到vi中。当基于某些原因希望使用非默认的shell时,这种技术就比较方便。
概况起来:
:!command 暂停vi,执行shell命令
:!! 暂停vi,执行前一条shell命令
:sh 暂停vi,启动一个新shell(默认shell)
:!bash 暂停vi,启动一个新Bash shell
:!tcsh 暂停vi,启动一个新Tcsh shell
:r命令有一种特别有用的变体:如果在:r命令之后不是键入文件的名称,而是键入一个!(感叹号),后面跟一个程序的名称,那么vi将执行该程序,并将程序的输出插入到编辑缓冲区当前行的下一行。
为了完结对:r命令的讨论,下面介绍一个节省时间的好方法,该方法可以展示该命令的强大功能。
假设当希望使用单词“ascetic”,但是不确定如何拼写这个单词。可以使用look命令显示字典文件中可能的单词:
look asc
假设正在使用vi向编辑缓冲区中键入文本,而此时正好希望将某个特定单词插入到文本中。按下<ESC>键从输入模式切换到命令模式,然后输入命令:
:r !look asc
look命令的输出将插入到当前行之后。查看列表并删除不希望的单词(look命令后的字符串越接近想要的单词,匹配的单词越少,删除不希望单词的工作量越小)。如果没有一个单词是需要的,可以使用u命令撤销插入。
当只留下正确的单词之后,就可以将光标移到所键入的最后一行,然后键入:
J
这样将把新单词连接到这一行的末尾。最后,为了返回到输入模式,准备在这一行的末尾插入文本,键入:
A
这样将允许在当前行末尾追加数据。
这一连串的命令看上去似乎挺复杂,但一旦习惯,便觉得非常简单。此外,双手无须离开键盘便可完成整件事情——很酷的体验。
:r命令概况如下:
:liner file 在指定行后插入文件file的内容
:r file 在当前行后插入文件file的内容
:liner !program 在指定行后插入程序program的输出
:r !program 在当前行后插入程序program的输出