Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

unix

posix

sh

Why can you can execute an empty file in bash, zsh, or sh and it will exit code 0 when an execve syscall with an empty file will exit ENOEXEC?

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

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

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 also calls execve and gets -ENOEXEC but it proceeds to read 80 bytes of the file and exit zero.

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)        
like image 1000
everett1992 Avatar asked Mar 16 '26 16:03

everett1992


1 Answers

If execve(2) returns an error and sets errno to ENOEXEC, all shells will try to run an executable file as a shell script, ie. they will exec a shell with the file given as argument. An empty script will have a zero exit status (= success) [1].

What shell will they run exactly depends: bash, ksh93 and yash will run the script themselves; csh, dash, zsh or mksh will always run it using /bin/sh.

This behavior is very old and predates the she-bang feature and the standardized executable file formats, and it's also required by the standard -- read the section 2. of Command Search and Execution from the standard.

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

It is however standard required behavior for the execvp() and execlp() library wrappers:

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] On older system /bin/true was a file consisting of just a copyright notice telling it's "unpublished proprietary source code of AT&T".


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!