vim
调用find | xargs
时,如下所示:find . -name "*.txt" | xargs vim
,您会收到有关
Input is not from a terminal
的警告,并且终端之后几乎没有行为。为什么会这样?
这个问题明确地是关于为什么,而不是如何避免。在其他地方有人问过,并回答过。
#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 楼
(根据引力的解释,xargs
将stdin
指向/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“ $ @” dev / tty'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 c
和ls | vim-open
配合使用评论
至于其他几个答案,请注意,实际问题是“为什么”,而不是“如何避免”。 (对此,我仍然要指出在我的问题下Trevor的评论是最可靠的方式,不需要脚本,别名或任何东西。)
–DevSolar
19年8月2日,9:25
评论
旁注:您可以完全在vim中执行此操作,而不用完全不使用find或xargs。打开不带参数的vim,然后运行:args ** / *。txt@TrevorPowell:这些年来,vim从未停止过让我惊叹。
相关:grep -l .. | xargs vim生成警告,为什么?在unix SE
相关:在Vim SE上使用xargs调用Vim后,终端出现故障。
GitHub错误报告:vim无法处理将STDIN设置为/ dev / null。