我将管道传输到 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
答案1
是的,当您执行以下操作时,进程会继承其父进程的文件描述符:
在
php -r 'passthru("nano");'
php
将继承 shell 的 stdin(如果在交互式 shell 的提示下调用,则为 tty 设备),并且也会继承它(而 stdout 是用于检索输出并传递它的nano
管道,似乎对它,并非所有编辑器都会这样做,您可能想在此处使用)。php
nano
nano
system()
在:
something | php -r 'passthru("nano");'
现在,您正在php
用它的 stdin 调用一个管道,something
另一端有 's stdout 。并将nano
继承它。
如果您希望php
的 stdin 成为管道,而nano
stdin 无论 shell 的 stdin 是什么,您需要以某种方式将该资源传递给php
,并使其php
(或由 运行的 shell passthru
)使其成为 的标准输入nano
。例如可以这样做:
{ something 3<&- | php -r 'passthru("nano <&3 3<&-");'; } 3<&0
我们使 fd 0 (stdin) 上的资源在命令组 ( {...;}
) 中的 fd 3 上也可用,为something
不需要它的 关闭它 ( 3<&-
),并告诉 php 运行的 shellpassthru
从该 fd 3 恢复 stdin 。
例子:
$ php -r 'passthru("ls -l /proc/self/fd");'
total 0
lrwx------ 1 stephane stephane 64 Mar 19 15:12 0 -> /dev/pts/38
l-wx------ 1 stephane stephane 64 Mar 19 15:12 1 -> pipe:[22538485]
lrwx------ 1 stephane stephane 64 Mar 19 15:12 2 -> /dev/pts/38
fd 0 是用于终端交互的 tty 设备。
$ echo hello | php -r 'passthru("ls -l /proc/self/fd");'
total 0
lr-x------ 1 stephane stephane 64 Mar 19 15:12 0 -> pipe:[22539326]
l-wx------ 1 stephane stephane 64 Mar 19 15:12 1 -> pipe:[22530020]
lrwx------ 1 stephane stephane 64 Mar 19 15:12 2 -> /dev/pts/38
现在ls
的 stdin 是一个管道(echo
正在馈送)。
$ { echo hello 3<&- | php -r 'passthru("ls -l /proc/\$PPID/fd /proc/self/fd <&3 3<&-");';} 3<&0
/proc/9202/fd:
total 0
lr-x------ 1 stephane stephane 64 Mar 19 15:17 0 -> pipe:[22544619]
lrwx------ 1 stephane stephane 64 Mar 19 15:17 1 -> /dev/pts/38
lrwx------ 1 stephane stephane 64 Mar 19 15:17 2 -> /dev/pts/38
lrwx------ 1 stephane stephane 64 Mar 19 15:17 3 -> /dev/pts/38
lr-x------ 1 stephane stephane 64 Mar 19 15:17 4 -> pipe:[22544623]
/proc/self/fd:
total 0
lrwx------ 1 stephane stephane 64 Mar 19 15:17 0 -> /dev/pts/38
l-wx------ 1 stephane stephane 64 Mar 19 15:17 1 -> pipe:[22544623]
lrwx------ 1 stephane stephane 64 Mar 19 15:17 2 -> /dev/pts/38
ls
的 stdin 已再次成为 tty 设备,而其父级 (php) 仍然具有 stdin 上的管道(另请参阅 fd 3 上的 tty 和 fd 4 上的另一个管道,可能是它正在读取ls
with 的输出的管道)。
所以在这里,您需要将 php 脚本更改为:
<?php
foreach(file("php://stdin") as $name) {
echo "Hello $name";
passthru("nano <&3 3<&-");
}
?>
并将其称为:
{ printf '%s\n' World Everybody | php script.php; } 3<&0
将两个资源(来自的管道printf
和原始标准输入)传递到php
.
如果您希望该php
脚本始终从终端内调用,并且nano
应该始终与终端交互(但话又说回来,请注意,这php
使得它标准输出 不是终端),您可以将其更改为:
<?php
foreach(file("php://stdin") as $name) {
echo "Hello $name";
passthru("nano < /dev/tty");
}
?>
我们将 的 stdin 硬编码nano
为控制终端。