Skip to main content

外部命令

在Unix系统内部,您会发现许多小型的,超专业化命令,每个命令只做一件事(而且能很好地完成)。您可以将这些命令链接在一起以共同解决一个复杂的问题。如果可以从Vim内部使用这些命令,那不是很好吗?

答案是肯定的!在本章中,您将学习如何扩展Vim以使其与外部命令无缝协作。

Bang 命令

Vim有一个Bang(!)命令,可以执行三件事:

1.将外部命令的STDOUT读入当前缓冲区。 2.将缓冲区的内容作为STDIN写入外部命令。 3.从Vim内部执行外部命令。

让我们一个个认真看一下。

将外部命令的标准输出STDOUT读入Vim

将外部命令的STDOUT读入当前缓冲区的语法为:

:r !{cmd}

:r是Vim的读命令。如果不带!使用它,则可以使用它来获取文件的内容。如果当前目录中有文件file1.txt,运行:

:r file1.txt

Vim会将file1.txt的内容放入当前缓冲区。

如果您运行的:r命令后面跟一个!和外部命令,则该命令的输出将插入到当前缓冲区中。要获取ls命令的结果,请运行:

:r !ls

它返回类似下列的文本:

file1.txt
file2.txt
file3.txt

您可以从curl命令读取数据:

:r !curl -s 'https://jsonplaceholder.typicode.com/todos/1'

r命令也接受一个地址:

:10r !cat file1.txt

现在,将在第10行之后插入来自运行cat file.txt的STDOUT。

将缓冲区内容写入外部命令

:w命令除了保存文件,还可以用来将当前缓冲区中的文本作为作为STDIN传递给外部命令。语法为:

:w !cmd

如果您具有以下表达式:

console.log("Hello Vim");
console.log("Vim is awesome");

确保在计算机中安装了node,然后运行:

:w !node

Vim将使用node执行Javascript表达式来打印"Hello Vim"和"Vim is awesome"。

当使用:w命令时,Vim使用当前缓冲区中的所有文本,与global命令类似(大多数命令行命令,如果不给它传递范围,则仅对当前行执行该命令)。如果您通过:w来指定地址:

:2w !node

"Vim"只使用第二行中的文本到node解释器中。

:w !node:w! node形式上区别很小,但功能上相隔千里。使用:w !node,您是将当前缓冲区中的文本"写入"到外部命令node中。用:w! node,则您将强制保存文件并将其命名为"node"。

执行外部命令

您可以使用bang命令从Vim内部执行外部命令。语法为:

:!cmd

要以长格式查看当前目录的内容,请运行:

:!ls -ls

要终止在PID 3456上运行的进程,可以运行:

:!kill -9 3456

您可以在不离开Vim的情况下运行任何外部命令,因此您可以专注于自己的任务。

过滤文本

如果给!范围,则可用于过滤文本。假设您有:

hello vim
hello vim

让我们使用tr (translate)命令将当前行大写。运行:

:.!tr '[:lower:]' '[:upper:]'

结果:

HELLO VIM
hello vim

命令分解:

  • .! 在当前行执行filter命令。
  • !tr '[:lower:]' '[:upper:]' 调用tr外部命令将所有小写字符替换为大写字符。

必须传递范围以运行外部命令作为过滤器。如果您尝试在没有.的情况下运行上述命令(:!tr '[:lower:]' '[:upper:]'),则会看到错误。

假设您需要使用awk命令删除两行的第二列:

:%!awk "{print $1}"

结果:

hello
hello

命令分解:

  • :%! 在所有行(%)上执行filter命令。
  • awk "{print $1}" 仅打印匹配项的第一列。

您可以使用管道运算符(|)链接多个命令,就像在终端中一样。假设您有一个包含这些美味早餐的文件:

name price
chocolate pancake 10
buttermilk pancake 9
blueberry pancake 12

如果您需要根据价格对它们进行排序,并且仅以均匀的间距显示菜单,则可以运行:

:%!awk 'NR > 1' | sort -nk 3 | column -t

结果:

buttermilk pancake 9
chocolate pancake 10
blueberry pancake 12

命令分解:

  • :%! 将过滤器应用于所有行(%)。
  • awk 'NR > 1' 仅从第二行开始显示文本。
  • |链接下一个命令。
  • sort -nk 3使用列3(k 3)中的值对数字进行排序(n)。
  • column -t以均匀的间距组织文本。

普通模式命令

在普通模式下,Vim有一个过滤运算符(!)。如果您有以下问候:

hello vim
hola vim
bonjour vim
salve vim

要大写当前行和下面的行,可以运行:

!jtr '[a-z]' '[A-Z]'

命令分解:

  • !j 运行常规命令过滤器运算符(!),目标是当前行及其下方的行。回想一下,因为它是普通模式运算符,所以适用语法规则"动词+名词"。
  • tr '[a-z]' '[A-Z]'将小写字母替换为大写字母。

filter normal命令仅适用于至少一行以上的motion或至少一行以上的文本对象。如果您尝试运行!iwtr'[az]''[AZ]'(在内部单词上执行tr),您会发现它在整个行上都应用了tr命令,而不是光标所在的单词。

聪明地学习外部命令

Vim不是IDE。它是一种轻量级的模式编辑器,通过设计可以高度扩展。由于这种可扩展性,您可以轻松访问系统中的任何外部命令。这样,Vim离成为IDE仅一步之遥。有人说Unix系统是有史以来的第一个IDE。

Bang 命令的有用程度与您知道多少个外部命令相关。如果您的外部命令知识有限,请不要担心。我还有很多东西要学。以此作为持续学习的动力。每当您需要过滤文本时,请查看是否存在可以解决问题的外部命令。不必担心掌握所有的命令。只需学习完成当前任务所需的内容即可。