Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Use:

  #!/usr/bin/env bash
Instead of:

  #!/bin/bash
This makes the script more portable as you don't rely on bash (or any executable) to be in /bin.

http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability



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.


Yes, using PATH for determining bash location is quite vulnerable to all kinds of security exploits.


  FreeBSD = /usr/local/bin/bash
  OpenBSD = /usr/local/bin/bash


> Are there any situations where you wouldn't be able to find bash in /bin/bash?

Yes there are.

OpenBSD for instance installs third party software under /usr/local. Bash is not a part of the base system.

env(1) on the other hand is a POSIX standard utility and comes with the OS.


[in addition to what clarry said] Habit of using /usr/bin/env becomes more important in other use-cases, such as invoking Python interpreter.


Exactly. I often use "#!/usr/bin/env python2" to specify python 2.x on my systems where python 3 is the default.


If you look after random mixtures of Linux and similar you'll be OK, but I've juggled OpenBSD , FreeBSD, Solaris, and Linux all at once.

Usually Solaris would get GNU tools installed beneath /opt, or similar, rather than in /bin.


OS X ships with an increasingly ancient version of bash owing to GPLv3. You probably want to use a later version installed with brew / port etc.


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.


and it doesn't work with bash-specific shell syntax, which will error upon script parsing in POSIX shells.


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 the purpose of the /bin directory was for the basic unix commands.

https://en.wikipedia.org/wiki/Unix_directory_structure#Conve...


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.

[1] https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard http://www.linuxfoundation.org/collaborate/workgroups/lsb/fh...


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.


Any {Free,Open,Net}BSD system.


>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.


If I want to be that portable, I just use #!/bin/sh and write a straight POSIX shell-compatible script instead.


The only real situation I'd like to use that is on Android, but it does not have /usr/bin/env either.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: