我有时尝试使用xargs调用Vim,就像这样:

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


…哪种工作方式: />当Vim启动时,我会短暂看到以下警告闪烁:


Vim: Warning: Input is not from a terminal



编辑工作— :files正确枚举了所有.java文件
我可以保存并退出。

但是,退出Vim后,我的终端坏了:提示没有回显。
根本没有出现回车,并且有时仅出现换行。

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

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

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

评论

我有点希望您填写尽可能多的问题,但是……这个问题多年来在SO / SU和其他地方已经被回答了数十次:xargs使用了一个虚拟的stdin,Vim无法使用然后破坏一切。

@romainl我在那些网站上并不活跃,而且我从未见过它问过这个问题-老实。

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

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

#1 楼

在调用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 + BSD xargs



在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


注意:Unix / OSX上的parallel无法工作,因为它具有不同的参数,并且不起作用。 t支持tty。

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

其他建议是使用:



ex命令行编辑器可解析数据或使用Ex模式,有关更多详细信息,请参见:

如何编辑文件n互动式(例如在管道中)?

vipe(Vim命令管道)

使用以下简单脚本:

#!/bin/sh
# usage: find ... | vip
exec vim < /dev/tty "$@"



相关信息:



错误GH-982:vim无法处理将STDIN设置为/ dev / null。

通过find调用vi | xargs破坏了我的终端。为什么?在超级用户SE

命令行中通过Vim exec命令和Vim:警告:输入不是来自stackoverflow上的终端

试图“定位”并在以下位置打开文件unix SE

less.vim在askubuntu SE上的Ubuntu 12.04 lts上不起作用

grep -l .. | xargs vim生成警告,为什么? unix SE上的[dup] Vim输入不是来自终端的输入。 ,文件还是目录中的所有文件?



评论


我的GNU xargs没有-J。这似乎是GNU版本中不存在的MacOS(BSD)选项。

–丹尼斯·威廉姆森
18年2月2日在21:34

#2 楼

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

使用vim -命令从stdin读取路径列表。 Vim的:help --对此进行了解释:1


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

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



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

解决方法:参数列表

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


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

#3 楼

除了reset之外,您还可以尝试:

stty sane


,这也将使您的终端再次可用。
以某种方式可以认为这是Vim的不当行为,至少Neovim目前没有此问题。

评论


这不能完全回答问题,但可以帮助我,所以+1。

–恢复莫妮卡-notmaynard
16-10-18在16:16

这确实回答了我的问题;)尽管在阅读了更多的OP之后,我想也应该进行重置。

– Sridhar Sarnobat
19年6月20日在17:47

#4 楼

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

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

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


-o将xarg的子进程的stdin(在本例中为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 -c的格式为bash -c 'COMMAND_STRING' "$@" etc

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

因此,在扩展</dev/tty之后,您将得到:

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


3。 stdin将执行COMMAND_STRING:

    </dev/tty vim file1 file2 


/dev/ttyvim设置为q4312079q,以便q4312079q可在交互模式下工作。

评论


+1这似乎是票数最高的答案的重复,但事实并非如此。 $ 0占位符(此处为“零”)是关键。

–丹尼斯·威廉姆森
18年11月2日在21:36



#5 楼

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

vim -O `grep -lir mySearchTerm *`



我将findxargsgrep结合使用没有问题,但是我发现语法令人讨厌。作为一个日常编码员,使用vim和终端作为他们的IDE,并不断在文件中搜索属性,这就是我一直在使用的东西。

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

希望对别人有帮助。

评论


FWIW建议不要使用旧的反引号,而应使用$(...)。它在命令行中不如在脚本中那么重要,但我认为最好在答案中使用它:)(此处和此处的引用)

–statox♦
19-10-11在8:04