Which one is better:

  • #!/usr/bin/env sh
  • #!/bin/sh
  • empty/no header

I used to think the 1st one is the best, anyway i've found on some Linux-based systems (like Android) that pathname is missing, so now i'm thinking the only way to have "portable" shell scripts is to not include any header...

  • It really is about how portable you want to be. Only Unixes ? All Linux-kernel based boxes ? All systems even old Win 3.0 and VMS (kidding) ? /bin/sh is usually a good minimum, just be aware that sh is not bash... expect on most GNU/Linux systems.
    – Ouki
    Mar 25, 2014 at 19:42
  • Although Android uses the linux kernel and the default shell is derived from bash via ash, the userland is not very unix-like and missing many standard tools.
    – goldilocks
    Mar 25, 2014 at 21:58

2 Answers 2


For portability, you can safely assume that #!/bin/sh will find a mostly POSIX-compliant shell on any standard Unix or Linux system, but that's really about it.

In FreeBSD, OpenBSD and NetBSD (along with DragonFly, PC-BSD and some other derivatives), bash is located at /usr/local/bin/bash (if it is installed), so the /usr/bin/env approach provides portability between Linux and BSD.

Android is not a standard Unix or Linux system. On my not-rooted Android phone, none of /usr/bin/env, /bin/bash or even /bin/sh exist, and the system shell is /system/bin/sh.

A shell script that is missing the #! (shebang) will attempt to run in the shell that called it on some systems, or may use a different default interpreter (/bin/bash for example), on other systems. And while this may work in Android, it isn't guaranteed to work in other operating systems, where users may elect to use an interactive shell that is not bash. (I use tcsh in FreeBSD, where it is the default shell, and shebang-less script are interpreted by the calling shell.)

So from where I sit, it looks like it is not possible to create a shell script that is portable between Android and non-Android (Linux or Unix) systems, because Android does things differently.

  • In my experience /bin/sh is supposed to point to something more like bsh or dash than bash, which is relatively bloated and thus preferred for interactive use.
    – Wutaz
    Mar 25, 2014 at 20:37
  • 2
    A few mistakes in here. There are still many (mostly commercial) Unices around here (most of them Solaris 10 and before) where /bin/sh is the Bourne shell, not a POSIX shell, POSIX doesn't specify the path of sh. Most shells (and execp/env/find -exec...) will interpret a she-bang-less script with the system's sh, few interpret it with themselves and when they do, they do it in POSIX compatibility mode. That's the standard/POSIX way to run script, but that assumes the caller is in a POSIX environment. Mar 25, 2014 at 20:38
  • Regarding *BSD bash is optional. It means there are good chances that even /usr/local/bin/bash does not exists on the systems (not to mention proprietary systems like Solaris, AIX or HP-Ux).
    – Ouki
    Mar 25, 2014 at 21:38
  • @StephaneChazelas - re POSIX, I agree of course, and that's why the words I used were "mostly POSIX-compliant". But this question was about portability, rather than where to find POSIX, and one can't rely on a shell always being found at one location. Regarding the default interpreter, a shebang-less script run in tcsh gets interpreted by tcsh on FreeBSD. Obviously, there's inconsistency there too, so I've updated the answer accordingly.
    – ghoti
    Mar 26, 2014 at 13:36
  • @Ouki - yes of course, I just didn't think that was relevant to the question. But I've added that clarification to the answer for clarity.
    – ghoti
    Mar 26, 2014 at 13:40

In my experience, #!/bin/sh and #!/bin/bash have always ended up finding the right environment on the few systems I have worked on. I am yet to encounter an exception. I also find it being used routinely in shell scripting related texts which I suppose are written keeping portability in mind because of diverse audience.

Can't say the same with #!/usr/bin/env. Some systems have it installed as #!/bin/env and have broken my python scripts in the past. So, I'll go with the second bullet.

Here is some supporting for my above statement:

On CentOS release 5.7 I get the following:

$ which env

On Ubuntu 12.04 Precise Pangolin:

$ which env

Additionally, at least in one older system, I remember the admins installed coreutils on /opt for some reason (may be not a best practice). Since env is part of coreutils, users ended up getting it at /opt/coreutils/bin/env. Admittedly, I have not used all the systems out there so the answer is based on my limited experience.

  • 5
    For instance /bin/bash is definitely not FreeBSD (would be /usr/local/bin/bash as bash is not part of the default shells).
    – Ouki
    Mar 25, 2014 at 19:37
  • 1
    It's rather the opposite: only some very rare systems lack /usr/bin/env (SCO which is barely extant, NextStep which is all but extinct — plus of course most common non-unix systems such as Android or Windows). On the other hand, /bin/bash pretty much only exists on non-embedded Linux. /bin/sh is a safe bet on any unix, but a few older systems have a non-POSIX Bourne shell there. Mar 25, 2014 at 23:26
  • @Gilles Thanks for the info. I updated my answer providing some evidence of what I have seen on some systems I have come across. Mar 26, 2014 at 2:05
  • 3
    which env isn't relevant: there are quite a few systems where /usr/bin is a symlink to /bin or vice versa, which makes both /usr/bin/env and /bin/env usable. What matters is that /usr/bin/env is present, which is the case on all Linux distributions I've ever seen or heard of (and removing it would break so many things that nobody would do it). Mar 26, 2014 at 9:53

Not the answer you're looking for? Browse other questions tagged or ask your own question.