中级应用

你提及使用yy命令剪切,并抱怨你几乎从来不会剪切整行。事实上程序员在编辑源代码时会经常涉及整行,连续的几行或代码块。yy只是把文本拷贝到匿名缓冲区(在vi中称为寄存器)的众多方式之一。

“vi”的禅在于你在使用一门语言。首个字母y是一个动词。语句yyy_的一个同义词。因为它是一个普通字符,重复一个y使它更容县键入。

yy类似的还有ddp(删除当前行,把当前行粘贴到某处并拷贝保存在匿名寄存器中)。yd可以把任何可编辑的文本当做操作对象。像yW操作的是当前光标到下一个词之前的文本。y'a操作的是当前光标到名为’a’的标记之间的文本。

如果你只会使用上下左右键来移动光标,那么对你来说使用vi在效率上来说并不会比你使用记事本要高(好吧,你还会获得代码高亮和轻松地处理比45KB还大的文本)。

vi有26个标记和26个寄存器。使用m命令可以在光标所在的任何位置设置一个标记。每个标记使用一个小写的英文字母来表示。像ma表示在光标所在处设置一个名为’a’的标记。mz表示在光标所在处设置一个名为’z’的标记。你可以使用单引号'把光标定位到标记所在的行。如'a表示把光标移到’a’标记所在的行行首。你还可以使用反引号`来移动光标到标记所在的确切位置。命令z将会移动光标到名为’(反引号)z’(抱歉,反引号+z 不懂怎么在反引号包围中转义)的标记的确切标记处。

上面所说的只是剪切和拷贝的一种方式而已。除了移动光标或使用标记外,我们还可以更简洁地操作。例如在一个文本段中,可以使用{}把光标移到到文本开头处和文本结尾处。如{d}命令将会剪切整个文本段。d}命令将会剪切当前光标所在处到文本结尾处之间的文本。d{命令将会剪切当前光标所在处到文本段开头之间的文本。

通常也会在vi中使用正则表达式。如使用d/foo命令来剪切当前光标到下一个名为”foo”的字符之间的文本。命令y?bar将会复制当前光标到前一个名为”bar”的字符之间的文本。

vi中我们还可以使用双引号"来使用26个寄存器。命令"add表示把当前行剪切到名为’a’的寄存器中。命令"b/foo表示把当前光标到下一下”foo”之间的文本复制到名为’b’的寄存器中。"ap表示把寄存器’a’中的文本粘贴到光标所在行的下一行。"aP表示把寄存器’a’中的文本粘贴到光标所在行的上一行。

作为一门语言,vi中也可以根据上下文环境使用形容词和副词修饰。如3J表示合并紧接着的三行。

以上的这些只不过是vi的一些中级应用。还没有涉及到Vim中的特殊用法。如果你打算学习vi的话,里面还是有许多高级特性需要学习的。

一些高级技巧

vi中有许多:命令。比较著名的有:%s/foo/bar/g全局替换的使用。一系列的:命令继承自名为’ed’和’ed’的扩展’ex’编辑器。事实上vi的得名也源于’ex’中的一个命令。

:系列命令通常作用于多行。ed和ex是上个年代终端显示屏还没流行大部分终端都是”teletype”(TTY)时的产物。因此:系统命令语法上带有一个作用域(从哪行到哪行)。:127,215 s/foo/bar表示把在第127行和第215行之间的文本中的”foo”替换为”bar”。也可以使用.$缩写符来表示当前行和尾行。使用+-表示当前行的后间隔和当前行的前间隔。如:.,$j表示把当前行和尾行之间的所有行合并成一行。:%命令与:1,$命令同义。

:... g:... v是极其强大的两个命令。:... g应用于所有匹配的结果集,:... v应用于所有不匹配的结果集。如:.,+21g/foo/d表示删除当前行和接下来的21行中所有包含”foo”字符的行。:.,$v/bar/d表示删除当前行和尾行之间所有不包含”bar”字符的行。

有趣的是Unix上grep命令的灵感正是来自ex中的命令。ex中的命令:g/re/p(grep)表示全局打印符合正则表达式’re’的内容。当使用ed和ex时,:p是每个人首先要掌握的命令。如:.,+25p表示打印当前行和接下来的25行。

我们还可以使用m命令和j命令来移动行或合并行。如果你想分离出一些匹配或不匹配的行而并不想删除它们。或许你会用到类似:% g/foo/m$的命令。它表示把包含有”foo”字符的行移到文件尾部。

需要注意的是你可以使用我们的老朋友s命令来代替gv命令。一般来说你不必这样做。但是对于一些复杂的匹配操作,你最好还是使用它。比如你想在你匹配出来的结果集中再匹配一些字符并替换它。如:% g/foo/s/bar/zzz/g命令表示找出包含”foo”字符的所有行,并在找出来的行中将字符”bar”替换成字符”zzz”。

:命令中的作用区间也可应用于标记。如:'a,'bg/foo/j表示合并标记a和标记b之间包含字符”foo”的上下两行。

注:文章大意译自StackOverflow上的一个回答,有删减。

(完)