xargs 和 vi -“输入不是来自终端”

xargs 和 vi -“输入不是来自终端”

我的系统上有大约 10 个php.ini文件,分布在各个地方,我想快速浏览它们。我尝试了这个命令:

locate php.ini | xargs vi

vi警告我Input is not from a terminal,然后控制台开始变得非常奇怪 - 之后我需要按:q!退出vi,然后断开与 ssh 会话的连接并重新连接以使控制台再次正常运行。

我想我有点明白这里发生了什么 - 基本上命令在vi启动时尚未完成,因此命令可能尚未完成并且vi不认为终端处于正常模式。

我不知道如何解决它。我搜索了 Google 和 unix.stackexchange.com,但运气不佳。

答案1

这个问题之前曾在超级用户论坛。

引用 @grawity 对这个问题的回答:

当您通过 xargs 调用程序时,程序的 stdin(标准输入)指向 /dev/null。 (由于 xargs 不知道原始的标准输入,因此它只能做次最好的事情。)

Vim 期望其标准输入与其控制终端相同,并直接在标准输入上执行各种与终端相关的 ioctl。当在 /dev/null (或任何非 tty 文件描述符)上完成时,这些 ioctl 毫无意义并返回 ENOTTY,它会被默默地忽略。

OS X/macOS/BSD 和 GNU findutils 的最新版本xargs(以v4.6.0)有一个-o选项可以解决这个确切的场景:

从 macOS/BSD 手册页:

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

因此,在 macOS 上,您可以使用以下命令:

find . -name "php.ini" | xargs -o vim

如果您坚持使用旧版本的 GNU xargs,则以下命令将起作用。 (确保包含该dummy字符串,否则它将删除第一个文件。)

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy

以上解决方案是礼貌的Jaime McGuigan 谈《超级用户》。将它们添加到此处,以供将来在网站上搜索此错误的任何访问者使用。

答案2

vi $(locate php.ini)

注意:如果您的文件路径包含空格、制表符、换行符(默认值为$IFS)或 glob 字符,这将会出现问题,但它在功能上与您的命令类似(xargs确实会特殊处理引号和反斜杠字符,而这不会)但不这样做)。
下一个版本将正确处理空格、制表符和全局字符,但有点复杂(文件名中的换行符仍然会破坏它)

(IFS=$'\n'; set -o noglob; vi $(locate php.ini))

解释:

发生的情况是程序从生成它们的进程继承它们的文件描述符。xargs其 STDIN 连接到 的 STDOUT locate,因此vi不知道原始 STDIN 到底在什么位置。

答案3

使用 GNUfindutils和支持进程替换的 shell(ksh、zsh、bash),您可以执行以下操作:

xargs -r0a <(locate -0 php.ini) vi

-a filename这个想法是通过 a而不是 stdin传递文件列表。使用-0可确保无论文件名包含哪些字符或非字符,它都可以正常工作。

有了zsh,你可以这样做:

vi ${(0)"$(locate -0 php.ini)"}

(其中0是在 NUL 上拆分的参数扩展标志)。

但请注意,如果没有找到文件,与此相反,xargs -r仍然可以在没有参数的情况下运行。vi

答案4

在同一个编辑器中编辑多个 php.ini ?

尝试: vim -o $(locate php.ini)

相关内容