shell script header for best compatibility

8,273

Solution 1

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.

Solution 2

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
/bin/env

On Ubuntu 12.04 Precise Pangolin:

$ which env
/usr/bin/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.

Share:
8,273

Related videos on Youtube

serhatg
Author by

serhatg

Updated on September 18, 2022

Comments

  • serhatg
    serhatg over 1 year

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

    • Admin
      Admin about 10 years
      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.
    • Admin
      Admin about 10 years
      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.
  • Ouki
    Ouki about 10 years
    For instance /bin/bash is definitely not FreeBSD (would be /usr/local/bin/bash as bash is not part of the default shells).
  • Wutaz
    Wutaz about 10 years
    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.
  • Stéphane Chazelas
    Stéphane Chazelas about 10 years
    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.
  • Ouki
    Ouki about 10 years
    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).
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 10 years
    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.
  • Ketan Maheshwari
    Ketan Maheshwari about 10 years
    @Gilles Thanks for the info. I updated my answer providing some evidence of what I have seen on some systems I have come across.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 10 years
    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).
  • ghoti
    ghoti about 10 years
    @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
    ghoti about 10 years
    @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.
  • Ouki
    Ouki about 10 years
    @ghoti: didn't ask for more ;) thanks
  • Stéphane Chazelas
    Stéphane Chazelas about 10 years
    The Bourne shell is not remotely POSIX compliant (POSIX sh is based on a subset of ksh88, with many extensions over the Bourne shell), but POSIX shells are mostly backward compatible with the Bourne shell. So, you can say that /bin/sh is likely to be mostly Bourne compatible, but not POSIX compliant unless you want to exclude all the Unices that still have the Bourne shell as their /bin/sh (though those are becoming rarer and rarer now that Solaris has moved to ksh for /bin/sh (at last))
  • Stéphane Chazelas
    Stéphane Chazelas about 10 years
    csh/tcsh will run the script with csh if the script starts with # and with sh otherwise as that's the historical behaviour before #! was invented and before the Bourne shell supported # as a comment leader. So in addition to leave off the she-bang, you may want to make sure the first character is not #.
  • ghoti
    ghoti about 10 years
    That may be the case where you are testing this, but in the OS I'm using, the behaviour is not as you describe. Please consider that what you describe as "historical behaviour" may not be universal. And we don't need to get into a debate about the "one true tcsh".