谁切断了进程替换文件的第一个符号,出于什么原因?

x-y*_*uri 4 pipe php

$ type 1.sh
#!/bin/bash -eu
php <(echo 12)
$ ./1.sh
2

$ type 2.sh
#!/bin/bash -eu
cat <(echo 12)
$ ./2.sh
12

$ type 3.sh
#!/bin/bash -eu
echo 12 | php
$ ./3.sh
12

$ type 4.sh
#!/bin/bash -eu
rm -f named_pipe
mknod named_pipe p
echo 12 > named_pipe
$ ./4.sh
$ php named_pipe   # from another window
2
Run Code Online (Sandbox Code Playgroud)

我在Debian( php-5.4.14, bash-4.1.5) 和Arch Linux( php-5.4.12, bash-4.2.42)上测试了它。

Gil*_*il' 5

当然是PHP。管道不会吃掉文件的第一个字符。PHP 正在读取所有字符,但没有输出第一个字符。到目前为止,您无法判断问题是在输入中还是在输出中:可能是 PHP 由于某种原因没有输出第一个字符。

一个小实验表明问题确实出在输入上。

$ php <(echo '<?php echo "hello" ?>') 
?php echo "hello" ?>
$ php <(echo ' <?php echo "hello" ?>')
hello$ 
Run Code Online (Sandbox Code Playgroud)

PHP 正在吃掉脚本的第一个字符,只有当脚本由文件名给出时(而不是当没有命令行参数并且从标准输入读取脚本时),只有当脚本文件是管道或其他不可搜索的文件(不是当脚本文件是可搜索的,例如当它是一个普通文件时)。

发生的事情是在开始时,在正常的 PHP 解析器启动之前,命令行处理器检查脚本是否以shebang行开头。如果脚本以两个字符开头#!,PHP 将跳过第一行。这样你就可以写一个像这样的PHP脚本

#!/usr/bin/php
first line
<?php echo "second line"?>
Run Code Online (Sandbox Code Playgroud)

该脚本将输出

first line
second line
Run Code Online (Sandbox Code Playgroud)

并且#!/usr/bin/php一开始没有虚假。

shebang 检测器是这样工作的:

  • 读取第一个字符。
  • 如果第一个字符是#,则读取另一个字符。
  • 如果前两个字符是#!,请继续阅读直到第一个换行符。
  • 如果前两个字符不是#!,则倒回到文件的开头。
  • 开始正常的 PHP 解析。

如果脚本文件不可搜索,则倒带步骤将失败,但 PHP 不会尝试检测该文件,因此文件的第一个字符将丢失(如果第一个字符是 a ,则第二个字符也会丢失#)。这是 PHP 命令行解释器中的一个错误。

您可以自己查看代码(在函数中cli_seek_file_begin)。