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

cwd*_*cwd 21 command-line terminal xargs vi

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

locate php.ini | xargs vi
Run Code Online (Sandbox Code Playgroud)

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

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

我不知道如何解决它。我已经搜索了谷歌和 unix.stackexchange.com 运气不好。

dar*_*nir 17

这个问题以前在超级用户论坛上被问过。

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

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

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

xarg 的手册页中提到了这一点。从 OSX/BSD:

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

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

find . -name "php.ini" | xargs -o vim
Run Code Online (Sandbox Code Playgroud)

虽然 GNU 版本没有直接开关,但此命令将起作用。(确保包含dummy字符串,否则会删除第一个文件。)

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy
Run Code Online (Sandbox Code Playgroud)

上述解决方案由SuperUser 上的 Jaime McGuigan 提供。将它们添加到此处,以供将来在网站上搜索此错误的任何访问者使用。

  • +1 感谢您的 -o 提示。我多年来一直在使用 xargs 并且从未注意到....只是检查了我系统上的手册页,那是因为它不是 GNU xargs 功能。手册页确实提供了`xargs sh -c 'emacs "$@" &lt; /dev/tty' emacs`,因为他们声称这是一种更灵活和可移植的替代方案(尽管 GNU 更喜欢可移植性对功能来说有点有趣: )。 (4认同)
  • `-o`(也称为 `--open-tty`)已被移植到 xargs (GNU findutils) 4.8.0。 (2认同)

phe*_*mer 14

vi $(locate php.ini)
Run Code Online (Sandbox Code Playgroud)

注意:如果您的文件路径有空格,这将有问题,但它在功能上等同于您的命令。
下一个版本将正确处理空格,但有点复杂(尽管文件名中的换行符仍会破坏它)

(IFS=$'\n'; vi $(locate php.ini))
Run Code Online (Sandbox Code Playgroud)


解释:

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

  • xargs 很棒,它是我最喜欢的工具之一 - 它不适合用于将 stdin 用于数据馈送以外的任何程序的程序。我喜欢你的回答和除此之外的解释,所以+1 :) (2认同)