为什么执行零字节文件时sh,zsh和bash返回零?

时间:2019-06-21 00:39:59

标签: unix sh posix

为什么您可以在bash,zsh或sh中执行一个空文件,而当带有空文件的execve syscall退出ENOEXEC时,它将退出代码0?

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

execveENOEXEC Exec format error退出-1,因此这不是操作系统行为。

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)        

1 个答案:

答案 0 :(得分:2)

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

它们将确切运行什么shell取决于:bashksh93yash将自己运行脚本; cshdashzshmksh将始终使用/bin/sh运行它。

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

  

execve-1 ENOEXEC退出Exec format error,因此这不是操作系统行为。

然而,execvp()execlp()库包装程序是standard必需的行为:

  

如果exec系列的其他成员        函数将失败,并将errno设置为ENOEXECexeclp()和        execvp()函数应执行命令解释器,并且        执行的命令的环境应类似于进程使用sh调用execl()实用程序,如下所示:

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

[1]在较旧的系统/bin/true上是一个仅包含版权声明的文件,该文件声明其为“ AT&T的未发布专有源代码”。