Are there any situations where you wouldn't be able to find bash in /bin/bash? I haven't ever seen such a system, but I'd like to know if it's something I might run into...
The other thing is, if you're targeting obscure systems, wouldn't it be just as likely that there wouldn't be a /usr/bin/env, /usr/ might not be mounted, or that bash might not be installed at all?
I suppose what I'm asking is: for practical purposes, is the lowest common denominator /usr/bin/env or is it /bin/sh?
The lowest common denominator is /bin/sh. But bash has a lot of niceties, and the POSIX shell can get the job done, but that lowest common denominator is pretty low. You're still going to be dealing with annoying differences on the platforms anyway.
I don't use env on my shebang lines specifically because it's then PATH ordering dependent (there used to be a thing where /usr/local/bin and GNU tools were last in root's path, but first in non-root users' path). I'm more confident (perhaps incorrectly) that /bin/bash or /usr/local/bin/bash is what I expect it is vs the first thing found in PATH that is named bash is what I think it is (however, this applies moreso to coreutils-like things, that have different SysV vs BSD semantics/options, vs a shell such as bash, which is known everywhere to be GNU bash). Some tools, like ssh, can propagate environment settings based on local, remote or config file settings, and I'd rather not be surprised.
This used to be a bigger deal on systems that put reasonable (where "reasonable" == "what you're used to") tools in /usr/ucb or /opt/gnu, rather than system paths. If you're going to create something that's intended to be "portable", you've got bigger fish to fry than if and where bash is available, and it's wise to abstract system differences to different scripts (run.linux.sh, run.freebsd.sh, run.osx.sh, run.aix.sh, etc) than try to keep everything in one massive script anyway.
Something along these lines would allow using bash without making your script completely broken:
#!/bin/sh
if [ -z "$BASH_VERSION" ]; then
if which bash >/dev/null 2>/dev/null; then
exec bash "$0"
else
echo "ERROR: bash was not in your PATH" >&2
exit 1
fi
fi
# now start using bash-only shortcuts safely
if [[ "hello" == "hello" ]]; then
echo Bash has been achieved.
fi
I'm not promising that's completely foolproof (it clearly isn't), but it works with the default Ubuntu 13.10 config of having /bin/sh linked to /bin/dash. And you could easily expand on the idea to look in specific locations for the bash binary even if it's not in the path, check those binary's versions, etc.
I have seen it in corporate environments where specific versions of things like bash (but more commonly, python, ruby, etc) are pushed to machines to places like /opt/ so that the deployed application could use them without fucking around with the package management of the underlying host. The deployed applications would then be kicked off in an environment with a modified PATH to reflect their dependencies being in those locations.
Those sort of deployments got a lot of milage out of /usr/bin/env
I always thought of it as the place for essential binaries needed for system rescue (single user boot). For this reason, they should also be statically linked. I got this a long time ago from reading the Filesystem Hierarchy Standard [1]
Not that this rule of thumb helps define the location of bash. It may or may not be considered essential for recovery.
Not necessarily statically linked, though IIRC OpenBSD's /bin/sh is for both robustness and security reasons. Debian distros offer an alternative sashroot login which uses the stand-alone shell, which is both statically linked and includes numerous additional built-ins useful for recovery or forensics work.
>Are there any situations where you wouldn't be able to find bash in /bin/bash?
Basically everything that isn't a typical gnu/linux distro or osx. Bash is not a standard tool, it is a gnu specific shell. Posix requires env to exist, and requires it to exist in /usr/bin/. If you are using bashisms, then using /usr/bin/env bash will let people without bash see that your script is a bash script, and install bash to solve the problem. If you hardcode /bin/bash they have to fix your script.
> is the lowest common denominator /usr/bin/env or is it /bin/sh
Ideally you should use /bin/sh of course. But it is missing functionality some people want to use, so in that case using bash the portable way is preferred over using bash the unportable way.
http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability