写入子进程的文件描述符(fd/0)

写入子进程的文件描述符(fd/0)

我正在我的 CentOS 7 沙箱中使用文件描述符。在这样做的过程中,我注意到一个有趣的情况。假设我们有一个简单的 PHP 脚本:

$step = 4 * 1024;

echo "php started\n";
while (!\feof(\STDIN)) {
    \fwrite(\STDOUT, 'read stdin part: '.\fread(\STDIN, $step)."\n");
}
echo "php finished\n";

我想从 bash 脚本中将其作为子进程在后台运行,并在标准输入中向其传递一些内容,如下所示:

php read.php &
phpProcId=$(ps axw -o pid,command | grep 'read' | head -1 | sed -r 's|^\s*([0-9]+)[^0-9]+.*$|\1|g')
echo "phpProcId: $phpProcId"
echo -e "test1\ntest2" >> /proc/$phpProcId/fd/0

但 shell 输出是:

$ sh box.sh
phpProcId: 2818
$ php started
read stdin part: 
php finished

看起来 bash 脚本在 PHP 脚本之前完成了工作,并且没有及时将其数据传递给 PHP 子进程。如何通过写入 php 子进程的 fd/0 来将数据传递给它?我确实了解 mkfifo 并且故意不想在这种情况下使用它。

答案1

我根本不懂PHP。这个答案是关于外壳的。

  1. 如果禁用作业控制[…],则在执行任何显式重定向之前,异步列表的标准输入应被视为分配给具有与/dev/null.如果启用作业控制,则不会发生这种情况。 […]

    来源

    sh当类似 shell 执行脚本时,默认情况下禁用作业控制。

    这意味着您php read.php &没有从某些 fifo 中读取;它也不与整个 shell 脚本共享 stdin。即使您正确地识别了它从中读取的文件(以/proc/…/fd/0或其他形式),写入该文件就像写入/dev/null,而不是写入 fifo。

    如果你真的想要打印/proc/…/fd/0并得到你想要的东西,那么你需要让它指向一些行为类似于 fifo 的东西,而不是像/dev/null;因此mkfifo这是一个明智的基本选择。

  2. 如果您认为需要,phpProcId那么可能phpProcId=$!比您使用的这个装置更好phpProcId=$(ps …)$!扩展为从当前 shell 执行的最近后台命令的十进制进程 ID。但也许你并不需要它,因为……

  3. 在 Bash 中,您可以创建一个文件描述符来打印到进程。在下面的示例中,该过程是cat -n

    exec 3> >(cat -n)
    # ...
    echo -e "test1\ntest2" >&3
    exec 3>&-
    

    这个未命名的 fifo 的写入部分在 we 时打开exec,描述符在 we 时关闭exec 3>&-(没有它:当 shell 退出时)。除非某些子进程继承该描述符并保持其打开状态,否则cat最终将退出,因为其标准输入在连接后不再连接到任何东西。即使我们不这样做echo,我们cat也会退出。

    cat请注意,在脚本退出后,您可能会看到交互式 shell 在打印提示之前或之后的输出。

  4. >(…)不能以普通形式工作sh。您标记了但调用了sh box.sh.如果需要,请使用bash(考虑使用 shebang)>(…)

相关内容