【问题标题】:How to write buffer content to stdout?如何将缓冲区内容写入标准输出?
【发布时间】:2010-07-10 14:07:20
【问题描述】:

有没有机会将当前vim缓冲区的内容写入stdout?

我想使用 vim 编辑通过 stdin 传递的内容 - 不需要临时文件来检索修改后的内容(在 Linux/Unix 上)。

是否有可能一个插件/脚本 - 在退出或保存时将缓冲区内容放入标准输出?

【问题讨论】:

  • 你没有说是什么平台,但:w! /dev/stdout "works" 在 linux 上"works" 的意思是"但是线路规则是原始的,所以它并不真正起作用"。
  • :w! /dev/stdout - 适用于 gvim 但对 vim 无用 ... hm
  • 这个问题构思不当,一般答案是否定的;为什么必须避免使用临时文件?
  • 问错了? - 我只是要求一种将vim缓冲区内容写入标准输出的方法,为什么不避免使用临时文件?没有临时文件,就少了一件事情需要处理——程序崩溃 tmp 文件仍然存在等。但没关系,如果答案是不可能的,我将不得不使用临时文件。要修改内容,需要用户交互 - 就像 miedwar 中的 crontab -e 案例 - 所以 sed、awk、perl 不是一个选项。
  • Pipe Vim buffer to stdout 的可能重复项

标签: shell vim stdout vi


【解决方案1】:

要将缓冲区打印到 shell 标准输出,vim 需要以 Ex 模式启动,否则它将以“正常”方式打开自己的窗口并在退出时清除所有输出缓冲区。

这是最简单的工作示例:

$ echo foo | vim -es '+%print' '+:q!' /dev/stdin
foo

需要指定标准输入的特殊文件描述符 (/dev/stdin) 以防止出现额外烦人的消息。

下面是一些字符串解析示例:

$ echo This is example. | vim -es '+s/example/test/g' '+%print' '+:q!' /dev/stdin
This is test.
$ echo This is example. | vim - -es '+s/example/test/g' '+%print' '+:q!'
Vim: Reading from stdin...
This is test.

这是一个使用ex 的简单示例,相当于vi -e

ex -s +%p -cq /etc/hosts

相关:

【讨论】:

  • 我不知道你可以用 +{command} 执行命令。我很高兴我找到了这个,因为我无法同时从标准输入读取和写入标准输出。
  • 好像%print 把空行变成了一个空格?你知道如何解决这个问题吗?例如,echo -n | vim -es '+%print' '+:q!' /dev/stdin | cat -etvecho | vim -es '+%print' '+:q!' /dev/stdin | cat -etv 输出 <space>$cat -etv 显示所有不可见字符,因此 $ == <newline>echo -n 是一个空输入,echo 是一个换行符输入。
【解决方案2】:

由于您使用 Linux/Unix,您可能也有兴趣尝试moreutils。它提供了一个名为vipe的命令,该命令从stdin读取,让您编辑$EDITOR中的文本,然后将修改后的文本打印到stdout

所以请确保将编辑器设置为 Vim:

export EDITOR=vim

然后你可以试试这些例子:

cat /etc/fstab | vipe
cut -d' ' -f2 /etc/mtab | vipe | less

【讨论】:

  • 谢谢 - vipe 也使用临时文件,但更多实用程序我还不知道,其中一些实用程序看起来非常有用
  • 很高兴了解moreutils。但是vipe使用的是临时文件,不适合我“解密文件,修改内容,加密结果”的应用。
  • moreutils/vipe 对我不起作用。它的行为在链式管道操作上不一致,导致目标文件的内容丢失。
【解决方案3】:

我认为:w !tee 会很好用,

【讨论】:

  • 你甚至可以在这个命令中使用管道。例如,我使用 gpaste command -range=% Copy :<line1>,<line2>w !tee | gpaste 定义命令“复制”以将特定行复制到剪贴板
  • 如果我忘记在没有 sudo 的情况下打开文件,这可以让我写 :w !sudo tee someFileThatNeedsSudo
  • :w !tee 不适用于 Vim 8 或 NeoVim。在 macOS 和 Linux 上测试:echo hello | vim '+wq! !tee'。传递-e 也不起作用,在+ 之后添加一个冒号也没有区别。
【解决方案4】:

这篇文章给了我一个想法:将缓冲区/或选择复制到剪贴板:

  1. 安装xclip(任何linux分发包管理器都应该有它。)

  2. 执行这个 vim 命令:

:w !xclip

如果您只想复制一些行,请先使用(普通模式)V 选择 tem,然后发出上述命令。

【讨论】:

    【解决方案5】:

    您可以使用 ex-mode (p)rint 命令来打印您想要标准输出的任何行集。

    打印所有行:

    :1,$p
    

    还打印所有行(% 是范围 1,$ 的简写)

    :%p
    

    打印第 4-10 行:

    :4,10p
    

    打印包含 FOO 的下一行

    /FOO/ p
    

    打印所有包含 FOO 的行

    g/FOO/ p
    

    【讨论】:

      【解决方案6】:

      vim 可以在管道中用作 全功能过滤器,并为 stdin 和 stdout 提供明确的名称,如下例所示:

      echo xxx                                             |
      vim                                                  \
        -esnN -i NONE                                      \
         +'1 s /x/y/g | 1 s /^/Hallo / | x! /dev/stdout'   \
         /dev/stdin                                        |
      cat -n
      

      - 缩写/dev/stdin 是行不通的,即使是-v 标志也不行。

      【讨论】:

      • 我注意到,此解决方案可能不适用于所有环境下所有环境中的所有 vim 实现,但大多数情况下效果很好。
      • 这很有趣,但我不确定“1 s”是如何进行替换或“x!”写入标准输出。 (我确实尝试在 vim 帮助中查找)
      • 我刚刚在 Cygwin、Debian Jessie、Knoppix 7.4、Mageia 5 和 Raspbian Jessie 下尝试了它,它在 bash 中的所有这些系统中都有效。替换的结果是 "Hallo yyy",vim 命令中行范围、命令和命令参数之间允许有空格,横杠是 vim 中的命令分隔符。
      • 如果通过 CGI 使用 vim,在某些系统配置下可能会出现问题。但是我没有发现这些系统之间的区别。相同的脚本可以在某些系统上完美运行,而在其他系统上则不行。它们可以通过存储到中间临时文件来避免。
      • 在运行 X 服务器的系统下,额外的标志 -X 防止等待 X 连接。
      【解决方案7】:

      从标准输入读取:

      echo "hey" | vim  -
      

      当你:w 时,你仍然需要给它一个文件名。

      使用vim 作为EDITOR 的程序,例如crontab -e 传递一个文件名,这样用户就可以只使用:x 而不必担心文件名。

      编辑

      你也可以这样做:

      mkfifo /tmp/some_pipe
      echo "hey" > /tmp/some_pipe ; cat /tmp/some_pipe
      

      从另一个进程(或终端)

      vim /tmp/some_pipe
      

      请注意,写入管道会阻塞,直到有东西从它读取,而读取会阻塞,直到有东西写入它,所以使用常规文件可能更安全。

      【讨论】:

      • 我用它通过 vim 读写加密文件。要打开 PGP 文件:pgpv < secret.pgp | vim -。编辑后::w !pgpe -co secret.pgp。在这种情况下,不要忘记禁用交换、备份、vimrc、历史记录等。
      【解决方案8】:

      使用:print 将写入标准输出,特别是当vim 使用-E-s 选项运行时,这会导致它以非交互方式和静默方式运行。见:h -E:h -s-ex

      The output of these commands is displayed (to stdout):
                              :print                          
                              :list
                              :number
                              :set      to display option values."
      

      使用:%print 打印整个当前缓冲区。

      【讨论】:

        【解决方案9】:

        尝试类似:

        { FROMCMD | vim - 8>&1 >&9 | tac | tac | TOCMD; } 9>&1
        

        完成编辑后使用 ':w !cat >&8'

        'tac | tac' 确保 TOCMD 在您完全 vim 之前不会接收任何数据,这仅在 TOCMD 写入终端时有用,这样它就不会在 vim 仍在运行时造成混乱。

        请注意,作为 TOCMD(或任何其他执行某些终端操作的程序)运行 'less' 不会按预期工作,因为即使您延迟数据,进程仍会“同时”启动,并且可能同时访问终端。

        【讨论】:

          【解决方案10】:

          您也可以使用pipe.vim。它确实使用了一个临时文件,但至少您不必在自己的脚本中担心它。

          对于问题的第二部分,您使用 vim 的 -s 命令行选项将 :w 重新映射到其他内容(如 :w !tee)。

          【讨论】:

            猜你喜欢
            • 2023-03-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-26
            • 1970-01-01
            • 2015-08-20
            • 2013-07-31
            相关资源
            最近更新 更多