使用xargs调用Vim后终端出现问题


30

我有时尝试使用调用Vim xargs,如下所示:

find . -name '*.java' | xargs vim

……哪种作品?

  1. Vim启动时,我会短暂看到以下警告闪烁:

    Vim: Warning: Input is not from a terminal
    
  2. 编辑工作— :files正确枚举了所有.java文件,如预期的那样。
  3. 我可以保存并退出。

但是,退出Vim后,我的终端很闷:

  • 我在shell提示符下键入的任何内容都不会回显。
  • 回车根本不出现,换行符有时仅出现。

直到我发出reset(1)命令重新初始化终端为止。

这是Vim的错误,还是关于它为何与终端交互的更令人满意的解释?我已经看到它发生在Linux和各种Unices上的7.3版的Vim上(该版本似乎无关紧要)。

我知道一种解决方法,即vim $(find . -name '*.java')。其他解决方法也将受到欢迎,尽管这不是我的主要问题。


我有点希望您填写尽可能多的问题,但是……多年来,这个问题在SO / SU和其他地方已经被回答了数十次:xargs使用了stdinVim不能使用的虚拟道具,并打破了之后的一切。
romainl 2015年

1
@romainl我在那些网站上并不活跃,我从未见过有人问过它-老实。
200_success,2015年

相关信息:superuser.com/questions/336016/…-也许有人可以将最重要的答案浓缩为一个好的答案。
muru 2015年

2
很好的问题-这件事在我身上无数次发生。另外,我不使用任何其他SO网站-如果它与vim有关,我想在这里找到它。
craigp 2015年

Answers:


21

这种情况发生在调用vim并将其连接到前一个管道的输出而不是终端并接收到不同的意外输入(如NUL)时。运行:时也会发生同样的情况vim < /dev/null,因此reset这种情况下的命令会有所帮助。超级用户粗俗解释可以很好地解释这一点。

如果您find用于传递文件名进行编辑,则不需要xargs,只需使用-exec,例如:

find . -name '*.java' -exec vim {} +

如果要使用xargs,在Unix / macOS上应使用-o参数,例如:

find . -name '*.java' | xargs -o vim

-o在执行命令之前,在子进程中以/ dev / tty重新打开stdin。如果您希望xargs运行交互式应用程序,这将很有用。

要么:

find . -name "*.java" -type f -print0 | xargs -o -0 vim

注意:使用-print0/ -0将支持带空格的文件名。


find+ BSDxargs

在Unix / macOS上,您可以尝试以下解决方法:

find . -name '*.java' | xargs -J% sh -c 'vim < /dev/tty $@'

您还可以使用命令替换语法,例如:

vim $(find . -name '*.java')
vim `find . -name '*.java`

或者,使用GNU parallel代替xargs强制tty分配,例如:

find . -name '*.java' | parallel -X --tty vi

注意:parallel在Unix / OSX上,由于参数不同且不支持tty,因此无法使用。

许多其他流行的命令也提供伪tty分配(如-t中的ssh),因此请查看帮助。

其他建议是使用:

有关:


我的GNU xargs没有-J。这似乎是GNU版本中没有的MacOS(BSD)选项。
暂停,直到另行通知。

12

解决方法建议:将缓冲区用作文件系统导航器

使用vim -命令从stdin读取路径列表。Vim的:help --解释是:1

开始编辑一个新的缓冲区,其中填充了从stdin读取的文本。现在通常将从stdin中读取的命令将从stderr中读取。例:

find . -name "*.c" -print | vim -

然后,您可以使用gfCtrl-wCtrl-f分别导航到同一缓冲区或新的拆分窗口中的文件。

解决方法建议:参数列表

另一个好方法是使用Vim的参数列表。该:argadd **/*.java命令将递归地使用在当前目录内找到的所有Java文件填充Vim的参数列表。然后,您可以使用:next:prev在文件之间移动。


1 -一个命令告诉Vim您要搜索帮助的命令行选项,第二个命令实际上是您要搜索的命令行标志。阅读:help help-context更多类似这样的技巧。


8

此外reset,您可以尝试:

stty sane

这也应该使您的终端再次可用。

参见这里的解释。而且某种程度上可以认为这是vim的不当行为,至少Neovim目前没有这个问题。


这不能完全回答问题,但可以帮助我,所以+1。
恢复莫妮卡iamnotmaynard

这确实回答了我的问题;)尽管阅读了OP之后,我想也reset应该更多。
Sridhar Sarnobat

1

原因是xargs设置stdin/dev/null,而vim需要stdin设置为/dev/tty


BSD xargs(例如Mac)解决方案:

echo -e 'file1\nfile2' | xargs -o vim

-ostdinxarg的子进程(vim在这种情况下)设置为dev/tty


GNU xargs(例如Linux)解决方案:

GNU xargs没有该-o选项。相反,您将不得不使用更复杂的解决方法。(注意:拥有结尾的zero字符串非常重要,请不要忘记它。)

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

您也可以将其设为别名:

alias vimin='xargs bash -c '\''</dev/tty vim "$@"'\'' zero'
echo -e 'file1\nfile2' | vimin

GNU xargs解决方案的详细说明

让我们将其逐步分解:

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

1. xargs只需将追加stdin到字符串的末尾,即可xargs执行以下操作:

    bash -c '</dev/tty vim "$@"' zero file1 file2

2.格式bash -cbash -c 'COMMAND_STRING' $0 $1 $2 etc

"$@"扩展为位置参数"$1", "$2"等。它不包含“ $ 0”,因为这是脚本名称的特殊参数,而不是位置参数。这就是为什么我们需要添加虚拟字符串zero(可以是任何字符串)代替的原因$0。否则,您将丢失第一个文件。

因此,扩展之后"$@",您将得到:

    bash -c '</dev/tty vim file1 file2' 

3. bash -c将执行COMMAND_STRING:

    </dev/tty vim file1 file2 

</dev/tty设置为stdin/dev/tty以便vim可以在交互模式下工作。


+1这似乎是票数最高的答案的重复,但事实并非如此。该$0占位符(这里是“零”)是关键。
暂停,直到另行通知。

0

我发现缺少所有这些答案。在解决了xargs问题之后,对我来说,最简单的方法-在通用框上进行以下搜索和打开操作如下:

vim -O `grep -lir mySearchTerm *`

findxargs和结合使用时没有问题grep,但是语法令人讨厌。作为日常的编码人员,我使用vim终端作为其IDE,并不断在文件中搜索属性,这就是我一直在使用的。

find . -path ./node_modules -prune -o -name '*.js' | xargs grep -i mySearchTerm通过vim和其他方法打开文件是有时间和地点的。对我来说,这很少。

希望这对某人有帮助。


2
FWIW建议不要使用旧的反引号,而应使用$(...)。在您的命令行中,它不如在脚本中那么重要,但是我认为最好在您的答案中使用它:)(此处此处的参考)
statox
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.