在通过vim调用find | xargs时,如下所示:

find . -name "*.txt" | xargs vim


,您会收到有关

Input is not from a terminal


的警告,并且终端之后几乎没有行为。为什么会这样?


这个问题明确地是关于为什么,而不是如何避免。在其他地方有人问过,并回答过。

评论

旁注:您可以完全在vim中执行此操作,而不用完全不使用find或xargs。打开不带参数的vim,然后运行:args ** / *。txt 从编辑器内部设置vim的参数。

@TrevorPowell:这些年来,vim从未停止过让我惊叹。

相关:grep -l .. | xargs vim生成警告,为什么?在unix SE

相关:在Vim SE上使用xargs调用Vim后,终端出现故障。

GitHub错误报告:vim无法处理将STDIN设置为/ dev / null。

#1 楼

通过xargs调用程序时,程序的stdin(标准输入)指向/dev/null。 (由于xargs不知道原始的stdin,所以它会做第二件事。)

qim1203qq

Vim希望其stdin与它的控制终端相同,并且直接在stdin上执行各种与终端相关的ioctl。当对/dev/null(或任何非tty文件描述符)进行处理时,这些ioctl毫无意义,并返回ENOTTY,这将被默默忽略。



我的猜测是更具体的原因:在启动时,Vim会读取并记住旧的终端设置,并在退出时将其恢复。在我们的情况下,当为非tty fd(文件描述符)请求“旧设置”时,Vim接收到的所有值都是空的,并且禁用了所有选项,并且不小心将其设置为终端。

您可以通过运行vim < /dev/null,退出它然后运行stty来看到此信息,这将输出大量<undef>。在Linux上,运行stty sane将使终端再次可用(尽管它将丢失iutf8之类的选项,以后可能会引起一些小麻烦)。


您可以认为这是Vim中的错误,因为它可以打开/dev/tty进行终端控制,但不能打开。 (在启动过程中的某个时候,Vim将其stderr复制到stdin,这使它可以从为写入而打开的fd读取输入命令,但即使这样做还不够早。)

评论


+1,而对于TL; DR人员来说,他们的目标是明智的

– doc_id
2015年2月11日在10:33

@rahmanisback:其他答案,加上Trevor的评论,都提供了避免终端损坏的方法。我接受了grawity的回答,因为我的问题是“为什么”,而不是“如何避免”,而这个问题实际上催生了这个问题。

–DevSolar
2015年2月11日在10:41



@DevSolar理解了,但是想想像我这样沮丧的人,他们只是谷歌如何摆脱这种行为,而不幸的是,现在没有足够的时间学习“为什么”,这仍然很有趣。

– doc_id
2015年2月11日在18:34

当我的终端出现故障时,像这样,我使用reset而不是stty sane,之后可以正常工作。

– Capi Etheriel
2015年4月21日在17:19

#2 楼

(根据引力的解释,xargsstdin指向/dev/null。)

解决此问题的方法是将-o参数添加到xargs
man xargs开始:


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


,因此,以下代码行应为您工作:

find . -name "*.txt" | xargs -o vim


自2017年以来,GNU xargs支持此扩展。
(长选项名称为--open-tty)。

对于旧版本或其他版本的xargs,
您可以显式传递/dev/tty来解决问题:

find . -name "*.txt" | xargs bash -c '</dev/tty vim "$@"' ignoreme


ignoreme占用$ 0,
所以$ @是所有参数来自xargs。)

评论


您将如何以此创建bash别名? $ @似乎不能正确转换参数。

– zanegray
2015年8月31日15:47



@zanegray-您不能创建别名,但是可以使其成为函数。试试:function vimin(){xargs sh -c'vim“ $ @”
–克里斯托弗(Christopher)
17年2月12日在18:02

有关GNU xargs解决方案的工作原理以及为什么需要虚拟的ignoreme字符串的详细说明,请参见vi.stackexchange.com/a/17813。

– Wisbucky
18年2月2日在20:42

@zanegray,您可以将其设为别名。引号很棘手。请参阅vi.stackexchange.com/a/17813上的解决方案

– Wisbucky
18年2月2日在20:46

-J,-o,-P和-R选项是非标准的FreeBSD扩展,在其他操作系统上可能不可用。 (由于我从自制软件(GNU版本)安装了xargs,因此在我的macOS上不可用。)

– localhostdotdev
19年5月7日在16:56

#3 楼

最简单的方法:

vim $(find . -name "*foo*")


评论


主要问题是“为什么”,而不是“如何避免”,并且两年半前人们对它的回答感到满意。

–DevSolar
2014年8月8日在9:35

当然,这在文件名包含空格或其他特殊字符时无法正常工作,并且也存在安全风险。

– Dejay Clayton
15年6月17日在16:14

我最喜欢的答案,因为它适用于列出文件的每个命令,而不仅仅是“查找”或通配符。正如Dejay指出的,确实需要一点信任。

–特拉维斯·威尔逊(Travis Wilson)
16年9月1日在20:50

这不适用于xargs设计的许多用例:例如,当路径数量非常多时(cc @TravisWilson)

–好人
16年11月30日在19:47

#4 楼

如果在find上使用-exec选项,而不是通过管道传递到xargs,它应该可以正常工作。

find . -type f -name filename.txt -exec vi {} + 


评论


呵呵...把这个东西加到一个(而不是“通常的” \;)中来把所有找到的文件都放入一个Vim会话中-这个选项我一直忘了。您当然是对的,为此+1。我只是出于习惯使用vim $ {find ...)。但是,我实际上是在问为什么管道操作会拧紧端子,而grawless则用他的解释来说明这一点。

–DevSolar
13年10月10日在18:45

这是最好的答案,它在BSD / OSX / GNU / Linux上均可使用。

–kevinarpe
2014年2月24日在17:17

同样,查找不是获取必须由vim同时编辑的文件列表的唯一方法。我可以使用grep查找带有模式的所有文件,然后尝试同时进行编辑。

– Chandranshu
2014年11月12日在8:41

#5 楼

改用GNU Parallel:

find . -name "*.txt" | parallel -j1 --tty vim


或者如果要一次打开所有文件:

find . -name "*.txt" | parallel -Xj1 --tty vim


甚至可以正确处理以下文件名:

My brother's 12" records.txt


观看介绍性视频以了解更多信息:http://www.youtube.com/watch?v=OpaiGYxkSuQ

评论


并非无处不在。大部分时间我都在不随意安装其他工具的服务器上工作。但是还是谢谢你的提示。

–DevSolar
2011年9月16日20:16在

如果您可以自由执行'cat> file; chmod + x file”,则可以安装GNU Parallel:这只是一个perl脚本。如果需要手册页等,可以将其安装在homedir下:./configure --prefix = $ HOME && make && make install

–奥雷·丹吉(Ole Tange)
2011年9月20日在9:09

OK,尝试过-但是parallel不会打开所有文件,而是会连续打开它们。一个简单的操作也很方便。 vim $(find。-name“ * .txt”)比较简单,您可以一次打开所有文件。

–DevSolar
2011年9月20日上午11:00

@DevSolar:有点无关,但都找到了| xargs和$(find)在文件名中的空格会有很大的问题。

–user1686
2011-09-20 18:34

@grawity正确,但是没有容易的方法(我知道)。您必须开始摆弄$ IFS,-print0和其他东西,然后离开一站式命令行解决方案的领域,并到达应该提出脚本的地步...这是有原因的,原因是空格不建议在文件名中使用。

–DevSolar
2011年9月21日在9:54

#6 楼

也许不是最好的,但这里是我使用的脚本(名为vim-open):

#!/usr/bin/env ruby

require 'shellwords'

inputs = (ARGV + (STDIN.tty? ? [] : STDIN.to_a)).map(&:strip)
exec("</dev/tty vim #{inputs.flatten.shelljoin}")


将与vim-open a b cls | vim-open配合使用

评论


至于其他几个答案,请注意,实际问题是“为什么”,而不是“如何避免”。 (对此,我仍然要指出在我的问题下Trevor的评论是最可靠的方式,不需要脚本,别名或任何东西。)

–DevSolar
19年8月2日,9:25