第22章 vi
文本编辑器
22.1 vi
重要的原因
kedit
gedit
Pico
Nano
POSIX / Single Unix Specification
22.2 vi
历史简介
ed em en ex vi
22.3 Vim
:vi
的备用编辑器
22.4 启动vi
^G
- 显示文件名称
22.5 启动Vim
:vim
vim -C [ -rR ] [ file… ]
-C compatibility mode
22.6 命令模式和输入模式
- 编辑缓冲区
editing buffer
Ctrl Shift
Return
Esc
- 命令模式
command mode
- 输入模式
input mode
22.7 了解所处模式的方式
:set showmode
22.8 以只读方式启动vi
:view
、vi –R
-R Read-only
22.9 系统失败后的数据恢复
vi -r test.c
-r recover
交换文件 swap file .test.c.swp
编辑完成后删除交换文件。
22.10 停止vi
!
字符有时候用来表示忽略某些类型的检查。
22.11 vi
使用屏幕的方式
插入控制字符 ^V
,后面跟希望输入的控制字符
制表符(8个空格) ^I
22.12 使用vi
和ex
命令
vi
命令- 单字母或双字母,无需
return
键:w
,dd
ex
命令- 以冒号开头,按
<Esc>
彻底取消命令,特殊键纠正命令
键 | 作用 |
---|---|
<Backspace><Delete> |
删除键入的最后一个字符 |
^W |
删除键入的最后一个单词 |
^X /^U |
删除整行 |
22.13 学习vi
命令的策略
- 移动光标的命令
- 进行输入模式的命令
- 进行修改的命令
22.14 创建一个练习文件
22.15 移动光标
-
将光标移动到上一行的开头
+/<Return>
将光标移动到下一行的开头
0
当前行的开头
$
当前行的末尾
^
当前行的第一个非空格/制表符的字符上
w
下一个单词词首
e
下一个单词词尾
b
上一个单词词首
大写忽略标点符号
)
——> 下一个句子
(
<—— 上一个句子
}
下一个段落
{
上一个段落
- 句子
- 的定义是一个字符串,以句号、逗号、问号或者感叹号结尾,后面至少跟两个空格或者一个新行字符。
- 段落
- 的定义为一个空白行开头并以一个空白行结束的一块文本区域。在行首放一个制表符来标志一个新段落是不够的。
22.16 在编辑缓冲区中移动
^F
forward
^B
backward
^D
down
向下移动半屏
^U
up
向上移动半屏
n ^D/D
设置跳转行数
22.17 跳转到前一位置
- “
- 连续键入两个反引号 返回前一位置
- ”
- 连续键入两个单引号返回前一位置的行首
以不可见的名称标记任意行
键入m
,后面跟一个字母,该字母就是这一行的名称。跳转到这一行可以键入一个反引号或一个单引号,后面跟这一行的名称。
22.18 搜索模式
:/
:?
n
N
使用正则表达式
元字符 | 含义 |
---|---|
. |
匹配除新行字符之外的任意单个字符(相当于? ) |
^ |
锚:匹配行的开头 |
$ |
锚:匹配行的末尾 |
\< |
锚:匹配单词的开头 |
\> |
锚:匹配单词的末尾 |
[list] |
字符类:匹配list 中的任何字符 |
[^list] |
字符类:匹配不在list 中的任何字符 |
\ |
引用:从字面上解析元字符 |
/M . .
/M[a-z][a-z]
/H[a-z]*y
22.19 使用行号
nG
跳转到第n
行 vi
1G
跳转到第1
行 vi
gg
跳转到第1
行 vi
G
跳转到最后一行 vi
:n
跳转到第n
行 ex
:1
跳转到第1
行 ex
:$
跳转到最后一行 ex
22.20 插入文本
都改变到输入模式:
i = insert a = append
i
光标位置之前
a
光标位置之后
I
当前行开头
A
当前行末尾
o
当前行下面
O
当前行上面
特殊键依然可以使用,不必离开输入模式。
^V^H
控制字符只算一个字符。
22.21 修改文本
r
精确修改一个字符(不进入输入模式)
R
改写,键入的每一个字符都覆盖当前行上的一个字符 R
替换文本时,vi
不会离开当前行,字符超过行尾,只是在这一行的末尾追加额外的字符
s
使用多个字符替换一个字符(**substitute)
C
替换从当前光标到行末的所有字符(change)
cc
替换一整行
S
替换一整行
cmove
以插入方式从当前光标替换到move
所给出的位置
22.22 替换文本(ex
)
命令 | 作用 |
---|---|
:s/pattern/replace/ |
都是ex 命令,substitute |
:s/UNIX/Linux |
替换当前行上该模式的第一个匹配项 |
:s/UNIX/Linux/gc |
g=global , c=confirm |
:sUNIX//g |
删除模式 |
:57s/UNIX/Linux/ |
替换特定行 |
:57,63s/UNIX/Linux/ |
替换指定范围的行 |
:.,$s/UNIX/Linux |
. 代表当前行,$ 代表最后一行 |
:%s/UNIX/Linux/cg |
% 代表所有行 |
22.23 删除文本
vi
命令:
`x` 删除光标处的字符
`X` 删除光标左边的字符
`D` 删除光标到行末的字符
`dmove` 删除光标到`move`所给位置处的字符
`dd` 删除当前行
d
与c
类似
ex
命令:
:line
d 删除指定行
:line,line
d 删除指定范围的行
22.24 撤销或重复改变
u
撤销上一命令对编辑缓冲区的修改
U
恢复当前行
.
重复上一命令对编辑缓冲区的修改
22.25 恢复删除
- 编号缓冲区
- number buffer(只存储删除的行)
vi
中一共有9
个这样的缓冲区,分别编号为1
至9
。将一个编号缓冲区中的内容插入到编辑缓冲区中,键入一个”(双引号),后面跟着一个p
或P
(put
,与o
类似)命令。
"1p "2p "1pu.u.u.u.u
在撤消了第一次插入之后,如果使用.
(点号)命令重复插入,那么vi
将自动地将缓冲区编号加1
。
22.26 移动文本
- 无名缓冲区
- unnamed buffer
p
无名缓冲区的内容插入到光标的右边
P
无名缓冲区的内容插入到光标的左边
xp
调换两个字符
deep
调换两个单词(光标开始处于第一个单词的左边)
ddp
调换两行
22.27 复制文本
- 使用
y
、yy
或Y
命令将文本由编辑缓冲区复制到无名缓冲区; - 将光标移动到希望插入文本的位置;
- 使用
p
或P
执行插入。
在不删除文本的情况下将文本复制到无名缓冲区时,称之为接出(yank
)了文本。
符号 | 作用 |
---|---|
yw |
接出了1 个单词 |
y10w |
接出了10 个单词 |
y10W |
接出了10 个单词(忽略标点符号) |
yb |
接出了1 个单词 |
y2( |
接出了2 个句子 |
y5} |
接出了5 个段落 |
yy |
接出1 行 |
10yy |
接出10 行 |
y0 |
接出了从当前字符到这一行开头之间的文本 |
y$ |
接出了从当前字符到这一行末尾之间的文本 |
Y = yy
y
与d
类似,yy
与dd
类似,Y
与D
完全不同。
22.28 改变字母的大小写
~
命令改变字母的大小写,然后光标向右移动一个位置。(大范围内连续使用~
时安全的)
对于有些vi
来说,~
命令不会越过一行的末尾。我的vim –C
就是如此。
22.29 设置选项
第一种类型的选项是开关(switch):set showmode noshowmode
第二种类型的选项是变量(variable) :set tabstop=4
开关 | 缩写 | 默认值 | 含义 |
---|---|---|---|
autoindent | ai | off | 和shift width有关,缩进以匹配上一行/下一行 |
autowrite | aw | off | 如果文本已经修改,则在切换文件前保存 |
errorbells | eb | off | 当现实错误消息时发出嘀嘀声 |
exec | ex | off | 在当前目录中查找初始化文件 |
ignorecase | ic | off | 在搜索过程中忽略大小写 |
list | — off | 将制表符显示为 | ^I ,将行的结束显示为$ |
number | nu | off | 显示行号 |
readonly | ro | off | 不允许修改编辑缓冲区的内容 |
showmatch | sm | off | 输入模式:显示匹配的() 、{} 和[] |
shownmode | smd | off | 当进入输入模式时显示一个提醒 |
wrapscan | ws | off | 在搜索过程中,环绕到文本的开头/ 末尾继续搜索 |
writeany | wa | off | 允许不需要重载!就可以写入任何文件 |
变量 | 缩写 | 默认值 | 含义 |
---|---|---|---|
lines |
- | 24 |
文本的行数 |
shiftwidth |
sw |
8 |
autoindent 使用的空格数 |
tabstop |
ts |
`8 | 制表符间距 |
wrapmargin |
wm |
0 |
设置自动换行时的页边距 |
22.30 显示选项
:set [ option [?]… | all ]
显示所有选项的值 :set all
显示一个选项的值 :set number?
显示改变了默认值的选项 :set
(读取初始化文件改变)
22.31 在键入过程中自动换行
:set wrapmargin=?
:set wm=?
22.32 分隔与连接行
将光标移到单词后的空格处,然后键入r<Return>
。r
命令使用新行字符取代空格,从而将行分隔。
将光标移动到第一行,并键入J(大写字母J
)将把当前行与下一行合并成一个长行,可以在J
命令之前放置一个重复次数。
22.33 复制与移动行(ex
)
在所有的ex命令中,.
(点号)代表当前行,$
代表编辑缓冲区中的最后一行,0
代表编辑缓冲区的开头。
:x [ , y ] co z
:x [ , y ] m z
在命令名称前面指定一个单独的行号或一个行号范围,这就是要移动的或复制的行。在命令名称之后,可以指定目标行号,新行将插入到目标行的下面。
:5co10 复制第5行到第10行下面
:4,8m20 移动第4至第8行插入到第20行的下面
交换缓冲区的上下两部分
:1 , . m $ : . , $ m 0
22.34 输入shell
命令
`:!command` 暂停`vi`,执行`shell`命令
`:!!` 暂停`vi`,执行最近一条命令
`:sh` 暂停`vi`,启动默认`shell`
`:!bash` 暂停`vi`,启动`bash`
`:!tcsh` 暂停`vi`,启动`tcsh`
22.35 将文件中的数据插入到编辑缓冲区中
:[ line ] r file
: r 命令读取文件的内容,并将该内容插入到编辑缓冲区中指定行之后。
:10 r info
:0 r info
:$ r info
如果省略了行号,vi
将把数据插入到当前行之后。
22.36 将shell
命令的输出插入到编辑缓冲区
:r
有一种特别有用的变体。如果在:r
命令之后不是键入文件的名称,而是键入一份!
(感叹号),后面跟一个程序的名称,那么vi
将执行该程序,并将程序的输出输入插入到编辑缓冲区中。
:r !ls
:0r !date
:line r file 在指定行后面插入文件file的内容
:r file 在当前行后插入文件file的内容
:line r !program 在指定行后插入程序program的输出
:r !program 在当前行后插入程序program的输出
22.37 使用程序处理数据:fmt
使用!
和!!
命令将把编辑缓冲区中的行发送给另一个程序,该程序的输出将替换原始行。
n!!program 在n个行上执行程序program
!move program 从当前行至move行执行程序program
将光标移到到希望处理的开始位置,键入希望处理的行数,后面跟!!
(两个感叹号)以及程序的名称,再后跟<Return>
键。
5!!sort 10!!fmt
!
(单感叹号)命令的工作方式与此相似,只是在!
命令在指定输入行的范围时更具有灵活性。
!}fmt
格式化整个编辑缓冲区
gg
!Gfmt
22.38 将数据写入文件
ex
命令w
,允许在不退出vi
的情况下,不时地备份数据。
`:w` 将数据写入原始文
`:w file` 将数据写入到一个新文件中
`:w! file` 覆盖一个已有的文件
`:w>>file` 将数据追加到指定的文件中
只保存编辑缓冲区中的特定行,则可以采用通常的方法指定行号。例如,为了将第10
行写入到文件save
中(替换save
的内容),可以输入:
:10w! save
为了将第10
行至第20
行追加到save
中,可以使用:
:10,20w>>save
:wq == <Shift>+ZZ`
22.39 切换到一个新文件
当开始编辑一个新文件时,编辑缓冲区中的原有内容将会丢失,所以要确保首先使用:w
命令将数据保存。
`:e file` 编辑指定的文件
`:e!` 重新编辑当前文件,忽略自动检查
`:e! file` 编辑指定的文件,忽略自动检查
22.40 使用缩写
为经常使用的单词或表达式创建缩写,使用:ab
(abbreviate,缩写)命令。
:ab [ sort long ]
:ab eg exception gifted
只有eg
是一个单词的时候才会进行替换,vi
不会替换其他单词中的eg,例如egotistical。
删除缩写:una
(un-abbreviate,反缩写)
:un short
通过输入:ab
命令本身查看所有的缩写列表。
22.41 宏(macro
)
允许创建自己的单字符命令,这些命令称之为宏(macro
)。(宏就是微型程序。)
:map [ x commands ]
x
是一个字符,commands
是vi
或ex
命令序列。
:map
命令可以创建宏,即vi
或ex
命令序列的缩写。宏名称必须是单个字符。如果选择早已拥有含义的字符作为命令,那么原有含义将会丢失。
例如:map K deep :map X dd
存在命令覆盖问题。
vi:
比较适合作为宏名称的字符
| 字母 | g
K
q
v
V
Z
|
|标点符号 | @
#
*
\
|
|Ctrl
字符 | ^A
^K
^O
^W
^X
|
Vim:
比较适合作为宏名称的字符
|字母 | K
q
v
V
|
|标点符号 | @
\
|
|Ctrl
字符| ^@
^A
^K
^O
^T
^X
|
例:
:map * I/*^V<Esc>A*/^V<Esc>
I
在行头进入输入模式。然后键入/*,
后面跟一个空格。此时,按<Esc>
退出输入模式。为了在宏中插入一个<Esc>
码,我们键入^V<Esc>
(^V[Ctrl
+
V]告诉vi
接下来的键要从字面上解释)。A
(append,追加)命令在行的末尾进入输入模式。然后键入一个空格,后面跟着*/
。退出输入模式,再次使用<Esc>
。
将宏赋给<F1>
到<F10>
的功能键。
:map #1 :set all
显示所有的宏列表:
:map
移除宏:
:unmap x x是宏的名称
22.42 初始化文件:.exrc
、.vimrc
vi .exrc dot-E-X-R-C
vim .vimrc dot-vim-R-C
rc run commands
vi/Vim
初始化文件样本
"==================================================
" Simple vi/Vim initialization file
"==================================================
"
"1.Option
set autoindent
set compatible
set showmatch
set showmode
set wrapmargin=6
"
"2.Abbreviations
ab eg exceptionally gifted
ab h Harley
"3.Maxros
map K deep
map X dd
map g 1G
map #5 {!}fmt^M
"4.shell commands
!date;sleep 2
22.43 使用两个初始化文件
一旦启动,vi
即在/home
中查找初始化文件,执行初始化文件中的命令后,vi
将查看exec
选项。如果选项是打开的,vi
即在当前目录中查找第二个初始化文件。
22.44 学习使用Vim
vimtutor