If a script /path/to/foo
begins with #!/bin/bash
, then executing /path/to/foo arg1 arg2
is equivalent to executing /bin/bash /path/too/foo arg1 arg2
. If the shebang line is #!/bin/bash -ex
, it is equivalent to executing /bin/bash -ex /path/too/foo arg1 arg2
. This feature is managed by the kernel.
Note that you can portably have only one argument on the shebang line: some unices (such as Linux) only accept one argument, so that #!/bin/bash -e -x
would lead to bash receiving the single five-character argument -e -x
(a syntax error) rather than two arguments -e
and -x
.
For the Bourne shell sh
and derived shells such as POSIX sh, bash, ksh, and zsh:
-e
means that if any command fails (which it indicates by returning a nonzero status), the script will terminate immediately.
-x
causes the shell to print an execution trace.
Other programs may understand these options but with different meanings.
Which shell executes scripts when there's no shebang line (#!/path/to/shell) at the beginning? I assume /bin/sh but I can't confirm.
The kernel refuses to execute such scripts and returns ENOEXEC, so the exact behavior depends on the program you run such a script from.
- bash 4.2.39 – uses itself
- busybox-ash 1.20.2 – uses itself
- dash 0.5.7 – runs /bin/sh
- fish 1.23.1 – complains about ENOEXEC, then blames the wrong file
- AT&T ksh 93u+2012.08.01 – uses itself
- mksh R40f – runs /bin/sh
- pdksh 5.2.14 – runs /bin/sh
- sh-heirloom 050706 – uses itself
- tcsh 6.18.01 – runs /bin/sh
- zsh 5.0.0 – runs /bin/sh
- cmd.exe 5.1.2600 – looks at you funny.
In glibc, functions execv()
or execve()
just return ENOEXEC. But execvp()
hides this error code and automatically invokes /bin/sh. (This is documented in exec(3p).)
What is considered "best practices" in terms of writing shell scripts that will run on any platform? (ok, this is sort of open-ended)
Either stick to sh
and only POSIX-defined features, or just go full bash (which is widely available) and mention it in your requirements if distributing it.
(Now that I think of it, Perl – or perhaps Python – would be even more portable, not to mention having a better syntax.)
Always add the shebang line. If using bash or zsh, use #!/usr/bin/env bash
instead of hardcoding the shell's path. (However, the POSIX shell is guaranteed to be at /bin/sh
, so skip env
in that case.)
(Unfortunately, even /bin/sh
is not always the same. The GNU autoconf program has to deal with many different quirks.)
Is it possible to write a script that tries to use zsh and falls back to bash if zsh is not available? I've tried putting two shebang lines, like below, but it just errors with bad interpreter: /bin/zsh: no such file or directory out if I try it on a machine without zsh.
There can only be one shebang line; everything after the newline character isn't even read by the kernel, and treated as a comment by shells.
It's possible to write a script that runs as #!/bin/sh
, checks which shell is available, and runs exec zsh "$0" "$@"
or exec bash "$0" "$@"
depending on the result. However, the syntax used by bash and zsh is so different in various places that I would not recommend doing this for your own sanity.
Best Answer
You can do wildcard commands like
ls *.rb
orcp *.sh
if you want to organize your scripts in the future.Start early or regret later, in my opinion.
Editors like
vim
will also be able to apply the correct syntax highlighting based on shebang or file extension.This can also be accomplished by using modelines in various editors. E.g. for vim: