Estou canalizando linhas em um script PHP (veja o exemplo artificial abaixo). Infelizmente, o pipe flui involuntariamente para o comando shell no script, portanto, o nano não é executado porque engasga com o STDIN.
Eu quero que o comando shell seja executado completamente sem relação com o STDIN canalizado para o script principal. Então o script PHP deve de certa forma "comer" o STDIN, para não atingir o sub-shell. Como faço para corrigir isso?
Note que exec()
, system()
e passthru()
todos dão o mesmo resultado.
$ echo -e "World\nEverybody" | php script.php
Hello World
Received SIGHUP or SIGTERM
Hello Everybody
Received SIGHUP or SIGTERM
script.php:
<?php
foreach(file("php://stdin") as $name) {
echo "Hello $name";
passthru("nano");
}
?>
Meio Ambiente:
- PHP 7.1.14 / PHP 5.6.30
- GNU bash, versão 3.2.57
Sim, os processos herdam os descritores de arquivo de seus pais, quando você:
Dentro
php
herdará o stdin do shell (um dispositivo tty se invocado no prompt de um shell interativo) enano
também o herdará (enquanto stdout é um canal usado porphp
para recuperar a saídanano
e passá-la,nano
parece estar feliz com isso, nem todos os editores fariam, você pode querer usarsystem()
aqui).Dentro:
Você está chamando
php
com ele stdin agora um tubo comsomething
stdout na outra extremidade. Enano
a herdará.Se você quiser que
php
o stdin seja o pipe, enquantonano
stdin seja qual for o stdin do shell, você precisa passar esse recurso de alguma forma paraphp
, e terphp
(ou o shell executado porpassthru
) torná-lo o stdin denano
. Isso poderia ser feito com, por exemplo:Onde disponibilizamos o recurso no fd 0 (stdin) também no fd 3 dentro de um grupo de comando (
{...;}
), fechamos parasomething
, que não precisa dele (3<&-
), e informamos ao shell executado pelos php'spassthru
para restaurar o stdin desse fd 3 .Exemplo:
fd 0 é um dispositivo tty para interação de terminal.
Agora
ls
o stdin é um pipe (aquele queecho
está alimentando).ls
O stdin do 's tornou-se o dispositivo tty novamente, enquanto seu pai (php) ainda tem o pipe no stdin (veja também o tty no fd 3 e outro pipe no fd 4, provavelmente aquele com o qual está lendo a saídals
).Então, aqui, você precisa alterar seu script php para:
E chame como:
Para passar os dois recursos (o pipe de
printf
e o stdin original) paraphp
.Se você espera que esse
php
script sempre seja chamado de dentro de um terminal e quenano
sempre interaja com o terminal (mas, novamente, observe quephp
o stdout não é o terminal), você pode alterá-lo para:Onde codificamos
nano
o stdin para ser o terminal de controle.