我的系统上有大约 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)