$ 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
)上测试了它。
当然是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 不会尝试检测该文件,因此文件的第一个字符将丢失(如果第一个字符是 a ,则第二个字符也会丢失#
)。这是 PHP 命令行解释器中的一个错误。
您可以自己查看代码(在函数中cli_seek_file_begin
)。