> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man1/vi.1.md).

# vi.1

`ex` — 文本编辑器

## 名称

`ex`, `vi`, `view`

## 概要

`ex [-FRrSsv] [-c cmd] [-t tag] [-w size] [file]`

`vi [-eFRrS] [-c cmd] [-t tag] [-w size] [file]`

`view [-eFrS] [-c cmd] [-t tag] [-w size] [file]`

## 描述

`vi` 是面向屏幕的文本编辑器。`ex` 是面向行的文本编辑器。`ex` 和 `vi` 是同一程序的不同界面，可以在编辑会话期间来回切换。`view` 等同于使用 `vi` 的 `-`（只读）选项。

本手册页是随 `nex`/`nvi` 版本的 `ex`/`vi` 文本编辑器提供的。`nex`/`nvi` 旨在作为原始第四版 Berkeley 软件发行版（4BSD）`ex` 和 `vi` 程序的 bug-for-bug 兼容替代品。在本手册页其余部分，仅在需要与 `ex`/`vi` 的历史实现区分时才使用 `nex`/`nvi`。

本手册页面向已熟悉 `ex`/`vi` 的用户。其他读者几乎都应该在阅读本手册页之前先阅读一份好的编辑器教程。如果你处于不熟悉的环境中，且必须立即开始工作，请阅读选项描述之后名为"快速入门"的章节。这大概足以让你上手。

可用选项如下：

**`-c`** `cmd` 在加载第一个文件时执行 `cmd`。特别适用于在文件中的初始定位，尽管 `cmd` 不限于定位命令。这是历史"+cmd"语法的 POSIX 1003.2 接口。`nex`/`nvi` 同时支持新旧两种语法。

**`-e`** 以 ex 模式开始编辑，如同命令名为 `ex`。

**`-F`** 首次开始编辑时不复制整个文件。（默认会制作副本，以防他人在你的编辑会话期间修改该文件。）

**`-`** 以只读模式开始编辑，如同命令名为 `view`，或设置了 `readonly` 选项。

**`-r`** 恢复指定文件，如果未指定文件，则列出可恢复的文件。如果指定名称的可恢复文件不存在，则如同未指定 `-r` 选项一样编辑该文件。

**`-S`** 以设置的 `secure` 编辑选项运行，禁止所有对外部程序的访问。

**`-s`** 进入批处理模式；仅适用于 `ex` 编辑会话。批处理模式在运行 `ex` 脚本时很有用。提示、信息性消息和其他面向用户的消息都会关闭，且不读取启动文件或环境变量。这是历史"-"参数的 POSIX 1003.2 接口。`nex`/`nvi` 同时支持新旧两种语法。

**`-t`** `tag` 在指定 `tag` 处开始编辑（参见 ctags(1)）。

**`-v`** 以 vi 模式开始编辑，如同命令名为 `vi`。

**`-w`** `size` 将初始窗口大小设置为指定的行数。

`ex`/`vi` 的命令输入从标准输入读取。在 `vi` 界面中，如果标准输入不是终端则会报错。在 `ex` 界面中，如果标准输入不是终端，`ex` 仍会从中读取命令；但是，该会话将是批处理模式会话，与指定 `-s` 选项完全相同。

## 快速入门

本节将告诉你使用 `vi` 完成简单编辑任务所需的最低限度知识。如果你从未使用过任何屏幕编辑器，即使阅读这个简单的介绍也可能遇到问题。在这种情况下，你应该找一个已经熟悉 `vi` 的人，让他们带你学习本节内容。

`vi` 是一个屏幕编辑器。这意味着它占据几乎整个屏幕，在每个屏幕行上显示文件的一部分，屏幕的最后一行除外。屏幕的最后一行用于你向 `vi` 发出命令，以及 `vi` 向你提供信息。

你需要理解的另一个事实是，`vi` 是一个有模式的编辑器，即你要么在输入文本，要么在执行命令，且必须在正确的模式才能执行其中之一。首次开始编辑文件时，你将处于命令模式。有命令可切换到输入模式。只有一个键可以让你退出输入模式，那就是 键。

本手册中，键名用 < 和 > 表示，例如 表示"escape"键，通常在终端键盘上标为"Esc"。如果你对自己处于哪种模式感到困惑，持续按 键直到 `vi` 对你发出蜂鸣声。一般情况下，如果你尝试做不被允许的操作，`vi` 会发出蜂鸣声。它也会显示错误消息。

要开始编辑文件，输入以下命令：

```sh
$ vi file
```

开始编辑后应立即输入的命令是：

```sh
:set verbose showmode
```

这会使编辑器给出详细的错误消息，并在屏幕底部显示当前模式。

在文件中移动的命令有：

**`h`** 光标左移一个字符。

**`j`** 光标下移一行。

**`k`** 光标上移一行。

**`l`** 光标右移一个字符。

**<`cursor-arrows`>** 光标方向键也应该可用。

**`/`** `text` 在文件中搜索字符串"`text`"，并将光标移到其第一个字符。

输入新文本的命令有：

**`a`** 在光标后追加新文本。

**`i`** 在光标前插入新文本。

**`o`** 在光标所在行下方打开新行，并开始输入文本。

**`O`** 在光标所在行上方打开新行，并开始输入文本。

**<`escape`>** 一旦使用 `a`、`i`、`o` 或 `O` 命令进入输入模式，使用 <`escape`> 退出文本输入并返回命令模式。

复制文本的命令有：

**`yy`** 复制光标所在行。

**`p`** 在光标所在行之后追加复制的行。

删除文本的命令有：

**`dd`** 删除光标所在行。

**`x`** 删除光标所在字符。

写文件的命令有：

**`:w`** 将文件写回，文件名为你最初在 `vi` 命令行上用作参数的名称。

**`:w`** `file_name` 将文件写回，文件名为 `file_name`。

退出编辑并退出编辑器的命令有：

**`:q`** 退出编辑并离开 `vi`（如果你修改了文件但未保存更改，`vi` 将拒绝退出）。

**`:q!`** 退出，丢弃你可能已做的任何修改。

最后一条注意事项：不寻常的字符可能在屏幕上占据多于一列，长行可能占据多个屏幕行。上述命令作用于"物理"字符和行，即它们影响整行，无论该行占据多少屏幕行；也影响整个字符，无论该字符占据多少屏幕列。

## 正则表达式

`ex`/`vi` 支持正则表达式（RE），如 re\_format(7) 中所述，用于行地址、`ex` 的 `substitute`、`global` 和 `v` 命令的第一部分，以及搜索模式。默认启用基本正则表达式（BRE）；如果启用了 `extended` 选项则使用扩展正则表达式（ERE）。可以使用 `magic` 选项在很大程度上禁用正则表达式的使用。

以下字符串在 `ex`/`vi` 版本的正则表达式中具有特殊含义：

* 空正则表达式等同于上次使用的正则表达式。
* ‘<’ 匹配单词开头。
* ‘>’ 匹配单词结尾。
* ‘\~’ 匹配上次 `substitute` 命令的替换部分。

## 缓冲区

缓冲区是命令保存已更改或已删除文本以备后用的区域。`vi` 缓冲区以双引号前缀的单个字符命名，例如 `"`<`c`>；`ex` 缓冲区相同，但没有双引号。`nex`/`nvi` 允许在期望缓冲区名称的位置使用任何没有其他含义的字符。

所有缓冲区要么处于 *行模式*，要么处于 *字符模式*。以行模式插入缓冲区到文本中时，会为其包含的每一行创建新行；而以字符模式的缓冲区会为除首行和末行之外的所有行创建新行。首行和末行在当前光标位置插入，成为当前行的一部分。如果缓冲区中有多行，当前行本身将被分割。所有将文本存储到缓冲区的 `ex` 命令都以行模式进行。`vi` 命令的行为取决于其关联的移动命令：

* <`control-A`>、`h`、`l`、`,`、`0`、**,** `E`、`F`、`T`、`W`、`^`、`b`、`e`、`f` 和 `t` 使目标缓冲区以字符为导向。
* `j`、<`control-M`>、`k`、`'`、`-`、`G`、`H`、`L`、`M`、`_` 和 `|` 使目标缓冲区以行为导向。
* `$`、`%`、`` ` ``、`(`、`)`、`/`、`?`、`[[`、`]]`、`{` 和 `}` 使目标缓冲区以字符为导向，除非起始和结束位置是某行的首字符和尾字符。在这种情况下，缓冲区以行为导向。

`ex` 命令 `display buffers` 显示每个缓冲区的当前模式。

名为 ‘a’ 到 ‘z’ 的缓冲区可使用大写等价形式引用，此时新内容将追加到缓冲区而非替换。

名为 ‘1’ 到 ‘9’ 的缓冲区是特殊的。使用 `c`（change）或 `d`（delete）命令修改的文本区域，如果未指定其他缓冲区且满足以下条件之一，则放入数字缓冲区 ‘1’：

* 包含多行字符。
* 使用面向行的移动指定。
* 使用以下移动命令之一指定：<`control-A`>、`` ` ``<`character`>、`n`、`N`、`%`、`/`、`{`、`}`、`(`、`)` 和 `?`。

在此复制完成之前，缓冲区 ‘1’ 的先前内容移入缓冲区 ‘2’，‘2’ 移入 ‘3’，依此类推。缓冲区 ‘9’ 的内容被丢弃。注意，此轮转发生 *无论* 用户是否指定了其他缓冲区。在 `vi` 中，文本可显式存储到数字缓冲区。在这种情况下，缓冲区轮转在替换缓冲区内容之前发生。数字缓冲区仅在 `vi` 模式下可用。

## VI 命令

以下章节描述 `vi` 编辑器命令模式下可用的命令。以下词语在命令描述中具有特殊含义：

**`bigword`** 一组非空白字符。

**`buffer`** 命令可放置文本的临时区域。如未指定，使用默认缓冲区。另参见上文"缓冲区"章节。

**`count`** 用于指定命令所需迭代次数的正数。如未指定，默认为 1。

**`motion`** 指示受影响文本区域另一端的光标移动命令，另一端为当前光标位置。重复命令字符使其影响整个当前行。

**`word`** 由字母、数字或下划线组成的序列。

`buffer` 和 `count`（如果都存在）可以按任意顺序指定。`motion` 和 `count`（如果都存在）实际上相乘，并视为移动的一部分。

**`+`** 如果指定了 `count1`，将行 `count1` 置于屏幕顶部。否则，显示当前屏幕之后的屏幕。

**<`carriage-return`>** 将行 `count1` 置于屏幕顶部。

**`.`** 将行 `count1` 置于屏幕中央。

**`-`** 将行 `count1` 置于屏幕底部。

**`^`** 如果给出 `count1`，显示 `count1` 之前的屏幕之前的屏幕（即 2 个屏幕之前）。否则，显示当前屏幕之前的屏幕。

<`control-A`> 从光标位置开始向前搜索单词。

\[`count`] <`control-B`> 向后翻 `count` 屏。如可能，保留两行重叠。

\[`count`] <`control-D`> 向前滚动 `count` 行。如果未给出 `count`，向前滚动上次 <`control-D`> 或 <`control-U`> 命令指定的行数。如果这是第一个 <`control-D`> 命令，滚动当前屏幕行数的一半。

\[`count`] <`control-E`> 向前滚动 `count` 行，如可能，保持当前行和列不变。

\[`count`] <`control-F`> 向前翻 `count` 屏。如可能，保留两行重叠。

<`control-G`> 显示以下文件信息：文件名（如传递给 `vi` 的）；文件自上次写入后是否已修改；文件是否为只读；当前行号；文件总行数；以及当前行号占文件总行数的百分比。

\[`count`] <`control-H`>

\[`count`] `h` 在当前行中将光标后退 `count` 个字符。

\[`count`] <`control-J`>

\[`count`] <`control-N`>

\[`count`] `j` 将光标下移 `count` 行，不改变当前列。

<`control-L`>

<`control-R`> 重绘屏幕。

\[`count`] <`control-M`>

\[`count`] `+` 将光标下移 `count` 行到该行的第一个非空白字符。

\[`count`] <`control-P`>

\[`count`] `k` 将光标上移 `count` 行，不改变当前列。

<`control-T`> 返回到最近的 tag 上下文。

\[`count`] <`control-U`> 向后滚动 `count` 行。如果未给出 `count`，向后滚动上次 <`control-D`> 或 <`control-U`> 命令指定的行数。如果这是第一个 <`control-U`> 命令，滚动当前屏幕行数的一半。

<`control-W`> 切换到窗口中的下一个较低屏幕，如果窗口中没有更低屏幕则切换到第一个屏幕。

\[`count`] <`control-Y`> 向后滚动 `count` 行，如可能，保持当前行和列不变。

<`control-Z`> 挂起当前编辑会话。

<`escape`> 执行正在输入的 `ex` 命令，或如果仅部分输入则取消。

<`control-]`> 将 tag 引用推入 tag 栈。

<`control-^`> 切换到最近编辑的文件。

\[`count`] <`space`>

\[`count`] `l` 将光标前移 `count` 个字符，不改变当前行。

\[`count`] `!` `motion shell-argument(s)` <`carriage-return`> 将 `count` 和 `motion` 跨越的行替换为由 `shell` 选项指定的程序的标准输出和标准错误，该程序以 `-c` 标志后跟 `shell-argument(s)`（捆绑为单个参数）调用。在 `shell-argument(s)` 中，‘%’、‘#’ 和 ‘!’ 字符分别扩展为当前文件名、上一个当前文件名以及上一个 `!` 或 `:!` 命令的命令文本。‘%’、‘#’ 和 ‘!’ 的特殊含义可通过反斜杠转义来覆盖。

\[`count`] `#` `# | + | -` 从光标位置或其后的第一个非空白字符开始，将光标下的数字递增（尾部 ‘#’ 或 ‘+’）或递减（尾部 ‘-’）`count`。以 ‘0x’ 或 ‘0X’ 开头的数字被解释为十六进制。以 ‘0’ 开头的数字被解释为八进制，除非包含非八进制数字。其他数字可带有 ‘+’ 或 ‘-’ 前缀。

\[`count`] `$` 将光标移到行尾。如果指定 `count`，额外将光标下移 `count` - 1 行。

**`%`** 移动到 `matchchars` 中与光标位置或其右侧最近的字符匹配的字符。

**`&`** 在当前行重复上一个替换命令。

`'<character>`

`` ` ``<`character`> 返回到由字符 `character` 标记的光标位置，或如果 `character` 是 ‘'’ 或 ‘`’，返回到以下命令中最后一个命令之前的光标位置：<`control-A`>、<`control-T`>、<`control-]`>、`%`、`'` 、`` ` \`\`、`(`、`)`、`/`、`?`、`G`、`H`、`L`、`[[`、`]]`、`{`、`}`。第一种形式返回到由 `character` 标记的行的第一个非空白字符。第二种形式返回到由 `character` 标记的行和列。

\[`count`] `(`

\[`count`] `)` 分别向后或向前移动 `count` 句。句子是从上一个句子、段落或章节边界之后的第一个非空白字符开始的文本区域，直到下一个句号、感叹号或问号字符，后跟任意数量的右括号、方括号、双引号或单引号字符，再后跟行尾或两个空白字符。空行组（或仅包含空白字符的行）视为单个句子。

\[`count`] `,` 反向查找字符（即上一个 `F`、`f`、`T` 或 `t` 命令）`count` 次。

\[`count`] `-` 移到上一行的第一个非空白字符，`count` 次。

\[`count`] `.` 重复上一个修改文本的 `vi` 命令。`count` 替换被重复命令的 `count` 参数及其关联 `motion` 的 `count` 参数。如果 `.` 命令重复 `u` 命令，则根据 `u` 命令的动作前滚或回滚更改日志。

/`RE` <`carriage-return`>

/`RE`/ \[`offset`] \[`z`] <`carriage-return`>

?`RE` <`carriage-return`>

?`RE`? \[`offset`] \[`z`] <`carriage-return`>

**`N`**

**`n`** 向前（‘/’）或向后（‘?’）搜索正则表达式。`n` 和 `N` 分别以相同或相反方向重复上次搜索。如果 `RE` 为空，使用上次的搜索正则表达式。如果指定 `offset`，光标置于匹配正则表达式之前或之后 `offset` 行。如果 `n` 或 `N` 命令用作 `!` 命令的移动组件，则不会提示命令文本，而是执行上一个 `!`。多个搜索模式可通过分号和零个或多个空白字符分隔来组合。这些模式从左到右求值，最终光标位置由最后一个搜索模式确定。可在闭合搜索表达式后追加 `z` 命令以重新定位结果行。

**`0`** 移到当前行的第一个字符。

**`:`** 执行 `ex` 命令。

\[`count`] `;` 重复上一个字符查找（即上一个 `F`、`f`、`T` 或 `t` 命令）`count` 次。

\[`count`] `<` `motion`

\[`count`] `>` `motion` 分别将 `count` 行左移或右移 `shiftwidth` 的量。

**`@`** `buffer` 将命名 `buffer` 作为 `vi` 命令执行。缓冲区也可包含 `ex` 命令，但必须以 `:` 命令表达。如果 `buffer` 为 ‘@’ 或 ‘\*’，则使用上次执行的缓冲区。

\[`count`] `A` 进入输入模式，在行尾追加文本。如果给出 `count` 参数，输入的字符在退出输入模式后重复 `count` - 1 次。

\[`count`] `B` 向后移动 `count` 个 bigword。

\[`buffer`] `C` 更改从当前位置到行尾的文本。如果指定 `buffer`，将删除的文本"拉入" `buffer`。

\[`buffer`] `D` 删除从当前位置到行尾的文本。如果指定 `buffer`，将删除的文本"拉入" `buffer`。

\[`count`] `E` 向前移动 `count` 个 bigword 的末尾。

\[`count`] `F` <`character`> 在当前行中向后搜索 <`character`> `count` 次。

\[`count`] `G` 移到第 `count` 行，如未指定 `count` 则移到文件最后一行。

\[`count`] `H` 移到屏幕顶部下方 `count` - 1 行的屏幕行。

\[`count`] `I` 进入输入模式，在行首插入文本。如果给出 `count` 参数，输入的字符重复 `count` - 1 次。

\[`count`] `J` 将 `count` 行与当前行合并。如果前一行以问号、句号或感叹号结尾，两行合并处的间距设为两个空白字符。否则设为一个空白字符。

\[`count`] `L` 移到屏幕底部上方 `count` - 1 行的屏幕行。

**`M`** 移到屏幕中间的屏幕行。

\[`count`] `O` 进入输入模式，在当前行上方新行追加文本。如果给出 `count` 参数，输入的字符重复 `count` - 1 次。

\[`buffer`] `P` 如果 `buffer` 以字符为导向，从 `buffer` 在当前列之前插入文本；如果以行为导向，则在当前行之前插入。

**`Q`** 退出 `vi`（或可视）模式并切换到 `ex` 模式。

\[`count`] `R` 进入输入模式，替换当前行中的字符。如果给出 `count` 参数，输入的字符在退出插入模式后重复 `count` - 1 次。

\[`buffer`] \[`count`] `S` 替换 `count` 行。如果指定 `buffer`，将删除的文本"拉入" `buffer`。

\[`count`] `T` <`character`> 在当前行中向后搜索指定 <`character`> 之后的字符，`count` 次。

**`U`** 将当前行恢复到光标上次移到该行之前的状态。

\[`count`] `W` 向前移动 `count` 个 bigword。

\[`buffer`] \[`count`] `X` 删除当前行光标前 `count` 个字符。如果指定 `buffer`，将删除的文本"拉入" `buffer`。

\[`buffer`] \[`count`] `Y` 将 `count` 行复制（或"拉取"）到 `buffer`。

**`ZZ`** 写入文件并退出 `vi`（如果没有更多文件要编辑）。连续输入两个"quit"命令会忽略任何剩余要编辑的文件。

\[`count`] `[[` 向后跨越 `count` 个章节边界。

\[`count`] `]]` 向前跨越 `count` 个章节边界。

**`^`** 移到当前行的第一个非空白字符。

\[`count`] `_` 下移 `count` - 1 行，到第一个非空白字符。

\[`count`] `a` 进入输入模式，在光标后追加文本。如果给出 `count` 参数，输入的字符重复 `count` 次。

\[`count`] `b` 向后移动 `count` 个 word。

\[`buffer`] \[`count`] `c` `motion` 更改由 `count` 和 `motion` 描述的文本区域。如果指定 `buffer`，将更改的文本"拉入" `buffer`。

\[`buffer`] \[`count`] `d` `motion` 删除由 `count` 和 `motion` 描述的文本区域。如果指定 `buffer`，将删除的文本"拉入" `buffer`。

\[`count`] `e` 向前移动 `count` 个 word 的末尾。

\[`count`] `f` <`character`> 在当前行的剩余部分向前搜索 <`character`> `count` 次。

\[`count`] `i` 进入输入模式，在光标前插入文本。如果给出 `count` 参数，输入的字符重复 `count` 次。

`m` <`character`> 将当前上下文（行和列）保存为 <`character`>。

\[`count`] `o` 进入输入模式，在当前行下方新行追加文本。如果给出 `count` 参数，输入的字符重复 `count` - 1 次。

\[`buffer`] `p` 从 `buffer` 追加文本。如果 `buffer` 以字符为导向，文本追加到当前列之后；否则追加到当前行之后。

\[`count`] `r` <`character`> 用 `character` 替换 `count` 个字符。

\[`buffer`] \[`count`] `s` 从当前字符开始替换当前行中的 `count` 个字符。如果指定 `buffer`，将替换的文本"拉入" `buffer`。

\[`count`] `t` <`character`> 在当前行中向前搜索紧邻 <`character`> 之前的字符，`count` 次。

**`u`** 撤销对文件的上次更改。如果重复，`u` 命令在这两个状态之间交替。紧随 `u` 之后使用 `.` 命令会根据 `u` 命令的动作前滚或回滚更改日志。

\[`count`] `w` 向前移动 `count` 个 word。

\[`buffer`] \[`count`] `x` 删除当前光标位置的 `count` 个字符，但不超过行尾。

\[`buffer`] \[`count`] `y` `motion` 将由 `count` 和 `motion` 指定的文本区域复制（或"拉取"）到缓冲区。

\[`count1`] `z` \[`count2`] `type` 重绘屏幕，可选地重新定位和调整屏幕大小。如果指定 `count2`，将屏幕大小限制为 `count2` 行。可使用以下 `type` 字符：

\[`count`] `{` 向后移动 `count` 个段落。

\[`column`] `|` 移到当前行上的指定 `column` 位置。如果省略 `column`，移到当前行的开头。

\[`count`] `}` 向前移动 `count` 个段落。

\[`count`] `~` `motion` 如果未设置 `tildeop` 选项，反转接下来 `count` 个字符的大小写，且不能指定 `motion`。否则 `motion` 是必需的，`~` 反转由 `count` 和 `motion` 指定的文本区域中字符的大小写。

<`interrupt`> 中断当前操作。 字符通常是 。

## VI 文本输入命令

以下章节描述 `vi` 编辑器文本输入模式下可用的命令。

<`nul`> 重放上次输入。

<`control-D`> 擦除到上一个 `shiftwidth` 列边界。

**`^`** <`control-D`> 擦除所有自动缩进字符，并重置自动缩进级别。

**`0`** <`control-D`> 擦除所有自动缩进字符。

<`control-T`> 插入足够的 和 字符以向前移动到下一个 `shiftwidth` 列边界。如果设置了 `expandtab` 选项，仅插入 字符。

<`erase`>

<`control-H`> 擦除最后一个字符。

<`literal next`> 转义下一个字符的任何特殊含义。 字符通常是 。

<`escape`> 将所有文本输入解析到文件中，并返回命令模式。

<`line erase`> 擦除当前行。

<`control-W`>

<`word erase`> 擦除最后一个 word。word 的定义取决于 `altwerase` 和 `ttywerase` 选项。

<`control-X`> \[`0-9A-Fa-f`] `+` 将指定十六进制值的字符插入文本中。

<`interrupt`> 中断文本输入模式，返回命令模式。 字符通常是 。

## EX 命令

以下章节描述 `ex` 编辑器中可用的命令。以下每个条目中，标记行是该命令的用法摘要。

**‘&’** 由 `pattern` 匹配的文本。

**‘\~’** 上一个 `substitute` 命令的替换部分。

**‘%’** 如果这是整个 `replace` 模式，则为上一个 `substitute` 命令的替换部分。

**‘#’** 其中 ‘#’ 是 1 到 9 的整数，由 `pattern` 中第 # 个子表达式匹配的文本。

**‘\L’** 使直到下一个 ‘\E’ 或 ‘\e’ 出现处为止的行尾之前的字符转换为小写。

**‘\l’** 使下一个字符转换为小写。

**‘\U’** 使直到下一个 ‘\E’ 或 ‘\e’ 出现处为止的行尾之前的字符转换为大写。

**‘\u’** 使下一个字符转换为大写。

<`end-of-file`> 滚动屏幕。

**`!`** `argument(s)`

\[`range`] `!` `argument(s)` 执行 shell 命令，或通过 shell 命令过滤行。

**`"`** 注释。

\[`range`] `nu`\[`mber`] \[`count`] \[`flags`]

\[`range`] `#` \[`count`] \[`flags`] 显示选定的行，每行前面带有行号。

**`@`** `buffer`

**`*`** `buffer` 执行缓冲区。

\[`range`] `<`\[`< ...`] \[`count`] \[`flags`] 左移行。

\[`line`] `=` \[`flags`] 显示 `line` 的行号。如果未指定 `line`，显示文件最后一行的行号。

\[`range`] `>`\[`> ...`] \[`count`] \[`flags`] 右移行。

`ab`\[`breviate`] `lhs rhs` 仅 `vi`。将 `lhs` 作为 `rhs` 的缩写添加到缩写列表。

\[`line`] `a`\[`ppend`] \[`!`] 输入文本追加到指定行之后。

**`ar`** \[`gs`] 显示参数列表。

**`bg`** 仅 `vi`。将当前屏幕置于后台。

\[`range`] `c`\[`hange`] \[`!`] \[`count`] 输入文本替换指定范围。

`chd`\[`ir`] \[`!`] \[`directory`]

`cd`\[`!`] \[`directory`] 更改当前工作目录。

\[`range`] `co`\[`py`] `line` \[`flags`]

\[`range`] `t` `line` \[`flags`] 将指定行复制到目标 `line` 之后。

`cs`\[`cope`] `add | find | help | kill | reset` 执行 Cscope 命令。

\[`range`] `d`\[`elete`] \[`buffer`] \[`count`] \[`flags`] 从文件中删除行。

`di`\[`splay`] `b`\[`uffers`] | `c`\[`onnections`] | `s`\[`creens`] | `t`\[`ags`] 显示缓冲区、Cscope 连接、屏幕或 tag。

\[`Ee`] \[`dit`] \[`!`] \[`+cmd`] \[`file`]

\[`Ee`] `x`\[`!`] \[`+cmd`] \[`file`] 编辑不同的文件。大写命令在当前屏幕下方打开新屏幕。

`exu`\[`sage`] \[`command`] 显示 `ex` 命令的用法。

`f`\[`ile`] \[`file`] 显示并可选地更改文件名。

\[`Ff`] `g` \[`name`] 仅 `vi` 模式。将指定屏幕置于前台。大写命令在当前屏幕下方打开新屏幕。

\[`range`] `g`\[`lobal`] /`pattern`/ \[`commands`]

\[`range`] `v` /`pattern`/ \[`commands`] 对匹配（‘global’）或不匹配（‘v’）模式的行应用命令。

**`he`** \[`lp`] 显示帮助消息。

\[`line`] `i`\[`nsert`] \[`!`] 输入文本插入到指定行之前。

\[`range`] `j`\[`oin`] \[`!`] \[`count`] \[`flags`] 将文本行连接在一起。

\[`range`] `l`\[`ist`] \[`count`] \[`flags`] 明确地显示行。

`map`\[`!`] \[`lhs rhs`] 定义或显示映射（仅用于 `vi`）。

\[`line`] `ma`\[`rk`] <`character`>

\[`line`] `k` <`character`> 用标记 <`character`> 标记该行。

\[`range`] `m`\[`ove`] `line` 将指定行移动到目标行之后。

`mk`\[`exrc`] \[`!`] `file` 将缩写、编辑器选项和映射写入指定 `file`。

\[`Nn`] \[`ext`] \[`!`] \[`file`] 从参数列表中编辑下一个文件。大写命令在当前屏幕下方打开新屏幕。

**`pre`** \[`serve`] 以可随后使用 `ex` `-r` 选项恢复的形式保存文件。

\[`Pp`] `rev`\[`ious`] \[`!`] 从参数列表中编辑上一个文件。大写命令在当前屏幕下方打开新屏幕。

\[`range`] `p`\[`rint`] \[`count`] \[`flags`] 显示指定行。

\[`line`] `pu`\[`t`] \[`buffer`] 将缓冲区内容追加到当前行。

`q`\[`uit`] \[`!`] 结束编辑会话。

\[`line`] `r`\[`ead`] \[`!`] \[`file`] 读取文件。

`rec`\[`over`] `file` 如果文件之前已保存，则恢复 `file`。

`res`\[`ize`] \[`+`|`-`] `size` 仅 `vi` 模式。增大或缩小当前屏幕。

`rew`\[`ind`] \[`!`] 回绕参数列表。

`se`\[`t`] \[`option` \[= \[`value`]]] \[`nooption` ...] \[`option?` ...] \[`all`] 显示或设置编辑器选项。

**`sh`** \[`ell`] 运行 shell 程序。

`so`\[`urce`] `file` 从文件读取并执行 `ex` 命令。

\[`range`] `s`\[`ubstitute`] \[/ `pattern` / `replace` /] \[`options`] \[`count`] \[`flags`]

\[`range`] `&` \[`options`] \[`count`] \[`flags`]

\[`range`] `~` \[`options`] \[`count`] \[`flags`] 进行替换。`replace` 字段可包含以下任何序列：

`su`\[`spend`] \[`!`]

`st`\[`op`] \[`!`]

<`suspend`> 挂起编辑会话。 字符通常是 。

\[`Tt`] `a`\[`g`] \[`!`] `tagstring` 编辑包含指定 tag 的文件。大写命令在当前屏幕下方打开新屏幕。

`tagn`\[`ext`] \[`!`] 编辑包含当前 tag 的下一个上下文的文件。

`tagp`\[`op`] \[`!`] \[`file | number`] 弹出到 tag 栈中指定的 tag。

`tagpr`\[`ev`] \[`!`] 编辑包含当前 tag 的上一个上下文的文件。

`tagt`\[`op`] \[`!`] 弹出到 tag 栈上最近的 tag，清空栈。

`una`\[`bbreviate`] `lhs` 仅 `vi`。删除缩写。

**`u`** \[`ndo`] 撤销对文件的上次更改。

`unm`\[`ap`] \[`!`] `lhs` 取消映射的字符串。

**`ve`** \[`rsion`] 显示 `ex`/`vi` 编辑器的版本。

\[`line`] `vi`\[`sual`] \[`type`] \[`count`] \[`flags`] 仅 `ex` 模式。进入 `vi`。

`Vi` \[`sual`] \[`!`] \[`+cmd`] \[`file`] 仅 `vi` 模式。通过在当前屏幕下方打开新屏幕来编辑不同的文件。

`viu`\[`sage`] \[`command`] 显示 `vi` 命令的用法。

`vs`\[`plit`] \[`+cmd`] \[`file`] 通过在当前屏幕右侧打开新屏幕来编辑不同的文件。

\[`range`] `w`\[`rite`] \[`!`] \[>>] \[`file`]

\[`range`] `w`\[`rite`] `!``shell-command`

\[`range`] `wn`\[`!`] \[>>] \[`file`]

\[`range`] `wq`\[`!`] \[>>] \[`file`] 写入整个文件或 `range`。‘!’ 覆盖不同的、已存在的文件。‘>>’ 追加到可能已存在的文件。空白后跟 ‘!’ 将文件通过管道传递给 `shell-command`。如果写入成功，`wn` 移到下一个文件。如果写入成功，`wq` 退出编辑器，除非还有更多文件要编辑；‘!’ 无论如何都退出。

\[`range`] `x`\[`it`] \[`!`] \[`file`] 退出编辑器，如果文件已修改则写入。

\[`range`] `ya`\[`nk`] \[`buffer`] \[`count`] 将指定行复制到缓冲区。

\[`line`] `z` \[`type`] \[`count`] \[`flags`] 调整窗口。

## 设置选项

有大量选项可设置（或取消设置）以更改编辑器的行为。本节描述这些选项、其缩写和默认值。

以下每个条目中，标记行的第一部分是选项的全名，后跟任何等效缩写。方括号中的部分是选项的默认值。大多数选项是布尔型，即它们要么打开要么关闭，没有关联值。

除非另有说明，选项同时适用于 `ex` 和 `vi` 模式。

**`altnotation`** \[off] 以 表示法显示小于 0x20 的控制字符。回车、escape 和 delete 分别标记为 、 和 ~~。~~

**`altwerase`** \[off] 仅 `vi`。选择备用 word 擦除算法。

**`autoindent , ai`** \[off] 自动缩进新行。

**`autoprint , ap`** \[on] 仅 `ex`。自动显示当前行。

**`autowrite , aw`** \[off] 更改文件或挂起编辑会话时自动写入已修改的文件。

**`backup`** \[""] 在覆盖文件之前备份。

**`beautify , bf`** \[off] 丢弃控制字符。

**`cdpath`** \[环境变量 `CDPATH`，或当前目录] `cd` 命令用作路径前缀的目录路径。

**`cedit`** \[无默认值] 设置用于编辑冒号命令行历史的字符。

**`columns , co`** \[80] 设置屏幕的列数。

**`comment`** \[off] 仅 `vi`。跳过 shell、C 和 C++ 语言文件中的前导注释。

**`directory , dir`** \[环境变量 `TMPDIR`，或 **/tmp**] 创建临时文件的目录。

**`edcompatible , ed`** \[off] 记住 `substitute` 命令的 ‘c’ 和 ‘g’ 后缀的值，而不是为每个新命令初始化为未设置。

**`errorbells , eb`** \[off] 仅 `ex`。以蜂鸣声通告错误消息。

**`escapetime`** \[1] `ex`/`vi` 等待后续键完成 键映射的十分之一秒数。

**`expandtab , et`** \[off] 在插入、替换或移动文本、自动缩进、用 <`control-T`> 缩进、用 <`control-D`> 减少缩进或用 `!` 命令过滤行时，将 字符扩展为 。

**`exrc , ex`** \[off] 读取本地目录中的启动文件。

**`extended`** \[off] 使用扩展正则表达式（ERE）而非基本正则表达式（BRE）。有关正则表达式的更多信息，请参见 re\_format(7)。

**`filec`** \[] 设置在冒号命令行上执行文件路径补全的字符。

**`fileencoding , fe`** \[自动检测] 设置当前文件的编码。

**`flash`** \[on] 出错时闪烁屏幕而非蜂鸣键盘。

**`hardtabs, ht`** \[0] 设置硬件 tab 设置之间的间距。此选项目前无效。

**`iclower`** \[off] 只要搜索字符串中不出现大写字母，就使所有正则表达式不区分大小写。

**`ignorecase , ic`** \[off] 在正则表达式中忽略大小写差异。

**`inputencoding , ie`** \[locale] 设置输入字符的编码。

**`keytime`** \[6] `ex`/`vi` 等待后续键完成键映射的十分之一秒数。

**`leftright`** \[off] 仅 `vi`。进行左右滚动。

**`lines , li`** \[24] 仅 `vi`。设置屏幕的行数。

**`lisp`** \[off] 仅 `vi`。修改各种搜索命令和选项以与 Lisp 配合使用。此选项尚未实现。

**`list`** \[off] 以明确的方式显示行。

**`lock`** \[on] 尝试对正在编辑、读取或写入的任何文件获取独占锁。

**`magic`** \[on] 关闭时，除 ‘^’ 和 ‘$’ 外的所有正则表达式字符都被视为普通字符。在单个字符前加 ‘\’ 可重新启用它们。

**`matchchars`** \[\[]{}()] `%` 命令查找的字符对。

**`matchtime`** \[7] 仅 `vi`。设置了 `showmatch` 选项时，`ex`/`vi` 在匹配字符上暂停的十分之一秒数。

**`mesg`** \[on] 允许来自其他用户的消息。

**`msgcat`** \[**/usr/share/vi/catalog/**] 选择用于以指定语言显示错误和信息性消息的消息目录。

**`modelines , modeline`** \[off] 读取每个文件开头和结尾几行以查找 `ex` 命令。此选项永远不会实现。

**`noprint`** \[""] 从不作为可打印字符处理的字符。

**`number , nu`** \[off] 在显示的每行前面加上当前行号。

**`octal`** \[off] 以八进制数而非默认的十六进制显示未知字符。

**`open`** \[on] 仅 `ex`。如果未设置此选项，则不允许 `open` 和 `visual` 命令。

**`optimize , opt`** \[on] 仅 `vi`。优化到哑终端的文本吞吐量。此选项尚未实现。

**`paragraphs , para`** \[IPLPPPQPP LIpplpipbp] 仅 `vi`。为 `{` 和 `}` 命令定义额外的段落边界。

**`path`** \[""] 定义搜索正在编辑的文件的额外目录。

**`print`** \[""] 始终作为可打印字符处理的字符。

**`prompt`** \[on] 仅 `ex`。显示命令提示符。

**`readonly , ro`** \[off] 将文件和会话标记为只读。

**`recdir`** \[**/var/tmp/vi.recover**] 存储恢复文件的目录。

**`redraw , re`** \[off] 仅 `vi`。在哑终端上模拟智能终端。此选项尚未实现。

**`remap`** \[on] 重新映射键直到解析。

**`report`** \[5] 设置编辑器报告更改或拉取的行数阈值。

**`ruler`** \[off] 仅 `vi`。在冒号命令行上显示行/列/百分比标尺。

**`scroll , scr`** \[窗口大小 / 2] 设置滚动的行数。

**`searchincr`** \[off] 使 `/` 和 `?` 命令增量搜索。

**`sections , sect`** \[NHSHH HUnhsh] 仅 `vi`。为 `[[` 和 `]]` 命令定义额外的章节边界。

**`secure`** \[off] 关闭所有对外部程序的访问。

**`shell , sh`** \[环境变量 `SHELL`，或 **/bin/sh**] 选择编辑器使用的 shell。

**`shellmeta`** \[\~{\[\*?$\`'"] 检查以确定是否需要文件名扩展的元字符集合。

**`shiftwidth , sw`** \[8] 设置自动缩进和移位命令的缩进宽度。

**`showfilename`** \[off] 仅 `vi`。在冒号命令行上显示文件名。

**`showmatch , sm`** \[off] 仅 `vi`。插入右侧匹配字符时注意左侧匹配字符。

**`showmode , smd`** \[off] 仅 `vi`。显示当前编辑器模式和"已修改"标志。

**`sidescroll`** \[16] 仅 `vi`。设置左右滚动每次的移动量。

**`slowopen , slow`** \[off] 延迟文本输入期间的显示更新。此选项尚未实现。

**`sourceany`** \[off] 读取非当前用户拥有的启动文件。此选项永远不会实现。

**`tabstop , ts`** \[8] 此选项设置编辑器显示的 tab 宽度。

**`taglength , tl`** \[0] 设置 tag 名称中有效字符的数量。

**`tags , tag`** \[tags] 设置 tag 文件列表。

`term , ttytype , tty` \[环境变量 `TERM`] 设置终端类型。

**`terse`** \[off] 此选项历史上使编辑器消息更简洁。在此实现中无效。

**`tildeop`** \[off] 修改 `~` 命令以接受关联的移动。

**`timeout , to`** \[on] 对可能被映射的键超时。

**`ttywerase`** \[off] 仅 `vi`。选择备用擦除算法。

**`verbose`** \[off] 仅 `vi`。为每个错误显示错误消息。

**`w300`** \[无默认值] 仅 `vi`。如果波特率小于 1200 波特，设置窗口大小。

**`w1200`** \[无默认值] 仅 `vi`。如果波特率等于 1200 波特，设置窗口大小。

**`w9600`** \[无默认值] 仅 `vi`。如果波特率大于 1200 波特，设置窗口大小。

**`warn`** \[on] 仅 `ex`。如果文件自上次写入后已修改，此选项导致在 `!` 命令之前在终端上打印警告消息。

`window , w , wi` \[环境变量 `LINES` - 1] 设置屏幕的窗口大小。

**`windowname`** \[off] 将图标/窗口名称更改为当前文件名。

**`wraplen , wl`** \[0] 仅 `vi`。从左边距起指定列数处自动断行。如果同时设置了 `wraplen` 和 `wrapmargin` 编辑选项，使用 `wrapmargin` 的值。

**`wrapmargin , wm`** \[0] 仅 `vi`。从右边距起指定列数处自动断行。如果同时设置了 `wraplen` 和 `wrapmargin` 编辑选项，使用 `wrapmargin` 的值。

**`wrapscan , ws`** \[on] 设置搜索在文件末尾或开头回绕。

**`writeany , wa`** \[off] 关闭文件覆盖检查。

## 环境变量

**`COLUMNS`** 屏幕上的列数。此值覆盖任何系统或终端特定值。如果 `ex`/`vi` 运行时未设置 `COLUMNS` 环境变量，或用户显式重置了 `columns` 选项，`ex`/`vi` 会将此值输入到环境中。

**`EXINIT`** `ex` 启动命令列表，在 **/etc/vi.exrc** 之后读取，除非也设置了变量 `NEXINIT`。

**`HOME`** 用户主目录，用作启动文件 `$HOME/.nexrc` 和 `$HOME/.exrc` 的初始目录路径。此值也用作 `cd` 命令的默认目录。

**`LINES`** 屏幕上的行数。此值覆盖任何系统或终端特定值。如果 `ex`/`vi` 运行时未设置 `LINES` 环境变量，或用户显式重置了 `lines` 选项，`ex`/`vi` 会将此值输入到环境中。

**`NEXINIT`** `ex` 启动命令列表，在 **/etc/vi.exrc** 之后读取。

**`SHELL`** 用户选择的 shell（另参见 `shell` 选项）。

**`TERM`** 用户的终端类型。默认类型为"unknown"。如果 `ex`/`vi` 运行时未设置 `TERM` 环境变量，或用户显式重置了 `term` 选项，`ex`/`vi` 会将此值输入到环境中。

**`TMPDIR`** 用于存储临时文件的位置（另参见 `directory` 编辑选项）。

## 异步事件

**`SIGALRM`** `vi`/`ex` 使用此信号定期备份文件修改，并在操作可能耗时较长时显示"忙碌"消息。

**`SIGHUP`**

**`SIGTERM`** 如果当前缓冲区自上次完整写入后已更改，编辑器会尝试保存已修改的文件以便日后恢复。更多信息请参见 `vi`/`ex` 参考手册的"恢复"章节。

**`SIGINT`** 发生中断时，当前操作停止，编辑器返回命令级别。如果在文本输入期间中断，已输入的文本将如同文本输入正常终止一样解析到文件中。

**`SIGWINCH`** 屏幕调整大小。更多信息请参见 `vi`/`ex` 参考手册的"调整屏幕大小"章节。

## 文件

**`/bin/sh`** 默认用户 shell。

**`/etc/vi.exrc`** 系统级 `vi` 启动文件。在启动序列中最先读取 `ex` 命令。必须由 root 或用户拥有，且仅所有者可写。

**`/tmp`** 临时文件目录。

**`/var/tmp/vi.recover`** 默认恢复文件目录。

**`$HOME/.nexrc`** 用户主目录启动文件的首选，在 **/etc/vi.exrc** 之后立即读取 `ex` 命令，除非设置了 `NEXINIT` 或 `EXINIT`。必须由 root 或用户拥有，且仅所有者可写。

**`$HOME/.exrc`** 用户主目录启动文件的次选，在与 `$HOME/.nexrc` 相同的条件下读取 `ex` 命令。

**`.nexrc`** 本地目录启动文件的首选，如果之前打开了 `exrc` 选项，则在启动序列末尾读取 `ex` 命令。必须由用户拥有且仅所有者可写。

**`.exrc`** 本地目录启动文件的次选，在与 `.nexrc` 相同的条件下读取 `ex` 命令。

## 退出状态

`ex` 和 `vi` 实用程序成功时退出值为 0，发生错误时大于 0。

## 参见

ctags(1), iconv(1), re\_format(7)

[Vi/Ex Reference Manual](https://docs.freebsd.org/44doc/usd/13.viref/paper.pdf)

## 标准

`nex`/`nvi` 接近 IEEE Std 1003.1-2008 ("POSIX.1")。该文档在若干处与历史 `ex`/`vi` 实践不同；双方都需要做出更改。

## 历史

`ex` 编辑器首次出现于 1BSD。`ex`/`vi` 编辑器的 `nex`/`nvi` 替代品首次出现于 4.4BSD。

## 作者

Bill Joy 于 1977 年编写了 `ex` 的原始版本。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man1/vi.1.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
