为什么在执行零字节文件时 sh、zsh 和 bash return 为零?

Why do sh, zsh, and bash return zero when executing a zero byte file?

为什么可以在 bash、zsh 或 sh 中执行一个空文件,并且当带有空文件的 execve 系统调用将退出 ENOEXEC 时,它会退出代码 0?

touch zero
chmod +x zero
./zero
echo $?
0

execve 退出的 -1 ENOEXEC Exec format error 所以这不是操作系统行为。

strace -f ./zero
execve("./zero", ["./zero"], [/* 53 vars */]) = -1 ENOEXEC (Exec format error)
write(2, "strace: exec: Exec format error\n", 32strace: exec: Exec format error
) = 32
exit_group(1)                           = ?
+++ exited with 1 +++

sh 也调用 execve 并获取 -ENOEXEC 但它继续读取文件的 80 个字节并退出零。

strace -f sh -c "./zero"
...
execve("./zero", ["./zero"], [/* 52 vars */]) = -1 ENOEXEC (Exec format error)
open("./zero", O_RDONLY)                = 3
read(3, "", 80)                         = 0
close(3)                                = 0
exit_group(0)        

如果execve(2) returns 出错并设置errnoENOEXEC,所有shell 将尝试运行 一个可执行文件作为 shell 脚本,即。他们将使用作为参数给出的文件执行 shell 。空脚本将具有零退出状态(= 成功)[1].

他们 运行 会 shell 完全取决于:bashksh93yash 将 运行 脚本本身; cshdashzshmksh 将始终 运行 使用 /bin/sh

此行为非常古老,早于 she-bang 功能和标准化的可执行文件格式,并且也是标准所要求的——请阅读标准中 Command Search and Execution 的第 2 节。

execve exit's -1 with ENOEXEC Exec format error so it isn't an operating systems behavior.

但是 standard execvp()execlp() 库包装器需要的行为:

In the cases where the other members of the exec family of functions would fail and set errno to ENOEXEC, the execlp() and execvp() functions shall execute a command interpreter and the environment of the executed command shall be as if the process invoked the sh utility using execl() as follows:

execl(<shell path>, arg0, file, arg1, ..., (char *)0);`

[1] 在旧系统上 /bin/true 是一个仅包含版权声明的文件,告诉它 "unpublished proprietary source code of AT&T"。