One of the delights in Bash, zsh, or whichever shell tickles your fancy in your OSS distribution of choice, is the ease of which you can use scripts. These can be shell scripts, or use the Perl, Python or another interpreter, as defined by the shebang (#!
) at the beginning of the script. This signature is followed by the path to the interpreter, which can be /bin/sh
for maximum compatibility across OSes, but how does this actually work? As [Bruno Croci] found while digging into this question, it is not the shell that interprets the shebang, but the kernel.
It’s easy enough to find out the basic execution sequence using strace
after you run an executable shell script with said shebang in place. The first point is in execve
, a syscall that gets one straight into the Linux kernel (fs/exec.c
). Here the ‘binary program’ is analyzed for its executable format, which for the shell script gets us to binfmt_script.c
. Incidentally the binfmt_misc.c
source file provides an interesting detour as it concerns magic byte sequences to do something similar as a shebang.
As a bonus [Bruno] also digs into the difference between executing a script with shebang or running it in a shell (e.g. sh script.sh
), before wrapping up with a look at where the execute permission on a shebang-ed shell script is checked.
Fun fact: you can script almost anything.
just use
#!/use/bin/env THEAPP
in the header of the file that you would send as an argument to the app, make the file executable und voila, you can run it.
I recently started to use those for ansible-playbook.
usr
damn you auto-correct!!
Call it auto-corrupt ;)
Another fun fact, posix allows a single argument to be added to the shebang, which becomes the first argument to the interpreter followed by the second argument path to the script.
(I think “env” allows for more than one arg)
So if your program normally requires something like “/bin/prog -file in.txt” you can instead start in.txt with “#!/bin/prog -file”
This is also why, regardless what fancy comment characters you want to support, you should also retain “#” as a comment symbol so the shebang line is ignored.
I learned to do this with python scripts during that time when python could mean either python 2 or 3.
A major use case for
binfmt_misc
is running a different processor’s binary on an otherwise incompatible platform.e.g. using
qemu-user-arm
viabinfmt_misc
tochroot
into a Raspberry Pi SD card from an AMD64 machine.