如何从命令提示符中运行一系列vim命令

58

我有四个文本文件A.txt、B.txt、C.txt和D.txt,需要对它们进行一系列的vim编辑。

目前我的做法是打开每一个文件,然后依次执行相同的vim命令。

是否有可能编写一个脚本文件,可以在命令提示符下运行,而不必打开实际文件进行vim编辑呢?

例如,如果我需要在vim编辑器中打开A.txt文件并执行以下vim命令:

:g/^\s*$/d
:%s/^/[/
:%s/\(.*\)\(\s\+\)\(.*\)/\3\2\1
:%s/$/]/
:%s/design/test/

是否可以创建一个脚本文件并将所有命令包括gvim A.txt(文件中的第一条命令)放入其中,然后从命令提示符运行脚本文件并编辑它。

如果可能的话,请告诉我如何做,并说明如何一次处理单个或多个文件?

6个回答

43
vim -c <command> Execute <command> after loading the first file

所述的内容是可以实现的,但需要逐个文件进行操作。

因此,在Windows shell中...

for %a in (A,B,C,D) do vim -c ":g/^\s*$/d" -c "<another command>" %a.txt

POSIX shell相似,但我现在面前没有一台机器。

我想你可以一次性加载所有文件并执行,但这需要针对每个文件在vim命令行上重复输入命令,类似于:

vim -c "<command>" -c "<command>" -c ":n" (repeat the previous -c commands for each file.)  <filenames go here>

编辑:2014年6月8日: 只是提醒一下,我几分钟前发现了这个。

vim有一个命令——bufdo,可对编辑器中加载的每个缓冲区(文件)执行操作。请查看bufdo命令的文档。在vim中键入:help bufdo


vim -c "<command>" -c "<command>" -c ":n" (对于每个文件重复前面的-c命令)<文件名在此处输入>这就是我的意思,非常感谢... - imbichie
1
请不要忘记在结尾处加上 -c ":wq" - sjas

36

直接在命令行中传递给Vim的-c命令数量限制为10个,这不太易读。相反,您可以将命令放入单独的脚本中并将其传递给Vim。以下是方法:

静默批处理模式

对于非常简单的文本处理(即使用Vim像增强版的'sed'或'awk'一样,可能只是从:substitute命令中受益于增强的正则表达式),请使用 Ex-mode

REM Windows
call vim -N -u NONE -n -es -S "commands.ex" "filespec"

注意:静默批处理模式(:help -s-ex)会破坏Windows控制台,因此您可能需要在Vim运行后执行cls来清理。
# Unix
vim -T dumb --noplugin -n -es -S "commands.ex" "filespec"

注意:如果不存在“commands.ex”文件,Vim将挂起等待输入;最好事先检查其是否存在!或者,Vim可以从stdin读取命令。如果使用“-”参数,您还可以从stderr读取命令并使用文本从stdin填充新缓冲区。
完全自动化:对于涉及多个窗口的更高级处理以及Vim的真正自动化(其中您可能需要与用户交互或让Vim保持运行以让用户接管),请使用:
vim -N -u NONE -n -c "set nomore" -S "commands.vim" "filespec"

以下是使用的参数摘要:
-T dumb           Avoids errors in case the terminal detection goes wrong.
-N -u NONE        Do not load vimrc and plugins, alternatively:
--noplugin        Do not load plugins.
-n                No swapfile.
-es               Ex mode + silent batch mode -s-ex
                Attention: Must be given in that order!
-S ...            Source script.
-c 'set nomore'   Suppress the more-prompt when the screen is filled
                with messages or output to avoid blocking.

讲解得很好。有没有办法将输出写入文件? 我试过用-w、-W、:w,但都没有帮助。 - Eashwar Gadanchi
通常,你会使用:write命令将内容写入输入文件或不同的文件名中,这样Vim就像高级的sedawk一样作为过滤器。在静默批处理模式下(也称为“完全自动化”),你还可以使用:print输出单个行和:verbose echomsg <MSG>输出任意文本; 这些将被打印到标准输出(你可以将其重定向到文件)。 - Ingo Karkat
为什么要使用--no-plugin代替-u NONE?对于Unix,似乎可以使用-N -u NONE -n -es -T dumb来启动。但我不确定每个选项的作用。并不是它们的功能,而是它们是否有区别。其中一些很可能会有区别。顺便说一下,不清楚哪些部分必须按特定顺序给出。哦,只有-es - x-yuri
@x-yuri:最后我提到两者都可以使用;这取决于使用情况。-u NONE 完全独立于用户设置,--no-plugin 避免了插件的耗时加载,但保留了用户的主要设置(因为默认设置不太友好)。如果您确实需要插件,则两者也可以省略,但这将对您的配置产生最大的耦合。 - Ingo Karkat

26

在保存有脚本的每个文件上运行所有你想要运行的命令,比如"script.vim"。你可以像其他人提到的那样在一个文件上执行该脚本:

vim -c "source script.vim" A.txt

更进一步,您可以在脚本的结尾处保存文件,方法是将:w命令放入脚本本身中,或者从命令行传递它:

vim -c "source script.vim | w" A.txt

现在,你可以使用argdo命令,在多个文件中运行任何Vim命令。 因此,你的命令变成:

vim -c "argdo source script.vim | w" A.txt B.txt C.txt D.txt

最后,如果你想在对每个文件运行脚本后退出 Vim,请添加另一个命令以退出:

vim -c "argdo source script.vim | w" -c "qa" A.txt B.txt C.txt D.txt

6
尝试使用以下语法:
ex foo.txt <<-EOF
  g/^\s*$/d
  %s/^/[/
  %s/\(.*\)\(\s\+\)\(.*\)/\3\2\1
  %s/$/]/
  %s/design/test/
  wq " Update changes and quit.
EOF
ex命令等同于vim -E。使用-V1参数可输出详细信息。
另一种行内语法示例如下:
ex +"g/^\s*$/d" +"%s/^/[/" +"%s/design/test/" -cwq foo.txt

要从文件中加载命令,请使用-s cmds.vim。您还可以使用shebang for Vim来解析参数中的文件。更多示例请参见:

2

JimR和Ingo为您的用例提供了出色的答案。

但是,为了增加另一种方法,您可以使用我的vimrunner插件以ruby脚本方式进行交互:https://github.com/AndrewRadev/vimrunner

示例:

vim = Vimrunner.start

vim.edit "file.txt"
vim.insert "Hello"
vim.write

vim.kill

这对于更复杂的交互非常有用,因为您可以获得编程语言的全部功能。


1

使用 vim -s ... 来脚本化冒号命令以及普通模式下的命令,例如使用 = 进行格式化:

  1. 创建一个包含你想要 vim 执行的所有按键的文件。
  2. 运行 vim -s SCRIPT-FILE FILE-TO-EDIT

例如:假设你想要使用 vim 的 = 命令重新缩进 myfile.html 的所有行。首先,使用 vim 本身创建一个名为 myscript 的文件,其内容如下:

gg=G:wq

(gg将光标移动到文件顶端;=G从当前位置重新缩进到文件末尾;:wq<Enter>保存文件并退出。)

然后,运行以下命令启动vim,编辑myfile.html并保存:

vim -s myscript myfile.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接