如何调用vim编辑器并将管道输出到bash


34

有时我需要编写文本,然后将其通过管道传递到另一个命令中。我通常的工作流程如下:

vim
# I edit and save my file as file.txt
cat file.txt | pandoc -o file.pdf # pandoc is an example 
rm file.txt

我觉得这很麻烦,并试图学习bash脚本,我想通过编写一个命令来触发该操作,从而简化该过程,该命令将打开编辑器,当编辑器关闭时,将编辑器的输出发送到stdout。这样我就可以将命令运行为quickedit | pandoc -o file.pdf

我不确定这将如何工作。我已经编写了一个函数,可以按照上面的确切工作流程以及一些附加操作来自动执行此操作。它生成一个随机字符串作为文件名,并在调用函数时将其传递给vim。当用户通过保存文件退出vim时,该函数将文件打印到控制台,然后删除该文件。

function quickedit {
    filename="$(cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32)"
    vim $filename
    cat $filename
    rm $filename
}
# The problem:
# => Vim: Warning: Output is not to a terminal

我很快遇到的问题是,当我执行诸如quickedit | commandvim之类的操作时,由于所有输出都被限制在管道中,因此本身不能用作编辑器。

我想知道是否有任何解决方法,以便可以通过管道输出quickedit函数的输出。次优的选择是启动一个单独的编辑器,例如sublime text,但是我真的想留在终端中。


在vim内部,发出命令:w !pandoc -o file.pdf?(注:之间的空间w!是必不可少的。)
John1024

太棒了。我不知道您可以从vim本身内部传递vim输出。这符合我的目的,但是就我将来的知识而言,是否可以完全按照我的预期解决问题?
theideasmith

您可以发布您的功能吗?当谈论即将遇到的问题时,您指的是什么(第二段)?我不明白
卢卡斯

5
顺便说一句,您应该使用mktemp而不是以不安全的方式重新发明它。
2016年

作为新的bash用户,重新发明mktemp有哪些安全隐患?
theideasmith '16

Answers:


42

vipe 是用于编辑管道的程序:

command1 | vipe | command2

您将获得一个具有完整输出的编辑器command1,当您退出时,其内容将通过command2管道传递给。

在这种情况下,没有command1。因此,您可以执行以下操作:

: | vipe | pandoc -o foo.pdf

要么:

vipe <&- | pandoc -o foo.pdf

vipe选择EDITORVISUAL变量,因此您可以使用它们来打开Vim。

如果尚未安装,vipe则可在moreutils包装中找到它。sudo apt-get install moreutils,或与您的口味相当的任何口味。


1
对于已到达此处的Mac用户:moreutilsHomebrew中可用。
vergenzt

对于FreeBSD用户:moreutils可通过pkg(8)安装。
Mateusz Piotrowski

20

您可以在Vim中执行此操作:

:w !pandoc -o file.pdf

甚至将缓冲区写入复杂的管道中:

:w !grep pattern | somecommand > file.txt

然后您可以不保存而退出Vim:

:q!

但是,考虑到您的特定用例,使用以下方法可能会有更好的解决方案 vi用作命令行编辑器。假设您使用bash

set -o vi

这会将您的键绑定设置为vi。因此,您可以vi通过按<Esc>然后输入以下内容来在命令行上使用基本的键盘绑定编辑命令vi如命令xcw等等。(您可以通过按回到插入模式i。)

甚至更好,并且与该问题更相关,您可以打开Vim来直接创建命令行内容。 只需输入<Esc>v,您将获得一个空的Vim缓冲区。保存并退出时,这就是命令行上的命令,它会立即运行。这比直接在命令行上编辑要灵活得多,因为您可以根据需要编写整个迷你脚本。


因此,例如,如果您想编写一些棘手的文本并将其立即发送到pandoc中,则可以键入:

<Esc>v

然后编辑Vim缓冲区,直到出现以下内容:

cat <<EOF | pandoc -o file.pdf
stuff for pandoc
more stuff for pandoc
EOF

然后保存并退出(使用:x),整个过程将作为shell命令运行。

它也将在您的Shell的命令历史记录中提供。


1
如果您希望保留Emacs的键绑定,仍然可以使用Vim来编辑命令行,方法是将EDITOR环境变量设置为vimCtrl-X然后Ctrl-E在编辑命令行时按。
安东尼·G-莫妮卡的大法官

18

在管道中运行

尝试:

quickedit() (  trap 'rm ~/temp$$' exit; vim ~/temp$$ >/dev/tty; cat ~/temp$$ )

关键是,要能够vim正常使用,vim需要stdout作为终端。我们在这里通过redirect来完成>/dev/tty

为了安全起见,我将临时文件放在用户的主目录中。有关更多信息,请参阅格雷格(Greg)的常见问题(FAQ)062。这样就无需使用晦涩的文件名。

例:

vim打开时,我输入This function succeeded.并保存文件。屏幕上的结果如下:

$ quickedit | grep succeeded
This function succeeded.

即使将的输出quickedit重定向到管道,也vim仍然可以正常工作,因为我们已将其直接访问/dev/tty

从vim中运行程序

正如我在评论中提到的那样,vim可以将文件通过管道传递给命令。例如,从vim内部发出命令:w !pandoc -o file.pdf(注意:w和!之间的空格是必不可少的)。


2
好答案。这直接解决了用户的问题,并提供了一种快速而优雅的解决方案:将vim重定向到/ dev / tty!简单!
Mike S

我正在使用Zsh;trap '...' exit失败,但trap '...' EXIT似乎可以工作。我对陷阱了解不多,但是我对临时文件的一般做法是使用mktmp [--suffix=...]。另外,vim <outfile> -c '...' >/dev/tty可以正常运行,直到加载文件为止,然后执行给定的命令链,包括:wq是否要跳过编辑阶段。我也用过set | grep -a EXIT,发现了signals=(EXIT ... DEBUG)
约翰·P

5

确保将vim其设置为默认编辑器(例如export EDITOR=vim,在.bash_profile或中.bashrc。),然后在任何提示下键入Ctrl- X后跟Ctrl- E。这将在已配置的编辑器中打开当前命令行(例如vim)。退出,该命令将被执行,就像您在命令行(包括管道等)上键入该命令一样。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.