我正在将行导入 PHP 脚本(请参见下面的人为示例)。唉,管道无意中流入脚本中的 shell 命令,因此 nano 无法运行,因为它在 STDIN 上阻塞。
我希望 shell 命令运行与通过管道传输到主脚本的 STDIN 完全无关。所以 PHP 脚本应该以某种方式“吃掉”STDIN,所以它不会到达子 shell。我该如何解决?
请注意exec()
,system()
和passthru()
都给出相同的结果。
$ echo -e "World\nEverybody" | php script.php
Hello World
Received SIGHUP or SIGTERM
Hello Everybody
Received SIGHUP or SIGTERM
脚本.php:
<?php
foreach(file("php://stdin") as $name) {
echo "Hello $name";
passthru("nano");
}
?>
环境:
- PHP 7.1.14 / PHP 5.6.30
- GNU bash,版本 3.2.57
是的,当您这样做时,进程会继承其父级的文件描述符:
在
php
将继承外壳的标准输入(如果在交互式外壳的提示下调用,则为 tty 设备)nano
并将继承它(而标准输出是用于php
检索输出nano
并传递它的管道,nano
似乎很满意它,不是所有的编辑都会,你可能想在system()
这里使用)。在:
你现在
php
用它调用 stdin 一个管道,something
另一端有 's stdout。并将nano
继承它。如果您希望
php
' 的标准输入成为管道,而nano
标准输入无论外壳的标准输入是什么,您都需要以某种方式将该资源传递给php
,并让php
(或由 运行的外壳passthru
)使其成为nano
. 例如,可以这样做:我们在命令组 () 中使 fd 0 (stdin) 上的资源在 fd 3 上也可用的地方,为不需要它的 ( )
{...;}
关闭它,并告诉 php 运行的 shell从该 fd 3 恢复标准输入.something
3<&-
passthru
例子:
fd 0 是终端交互的 tty 设备。
Now
ls
的标准输入是一个管道(一个echo
正在喂食)。ls
的 stdin 已再次成为 tty 设备,而其父 (php) 仍然在 stdin 上有管道(另请参见 fd 3 上的 tty 和 fd 4 上的另一个管道,可能是它正在读取输出的管道ls
)。所以在这里,您需要将您的 php 脚本更改为:
并将其称为:
将两种资源(来自的管道
printf
和原始标准输入)传递给php
.如果您希望
php
始终从终端内调用该脚本,并且该脚本nano
应始终与终端交互(但再次注意,php
使其标准输出 不是终端),您可以将其更改为:我们将
nano
's stdin 硬编码为控制终端。