No, I’m not talking about adding sound-effects to my blog. I’d like to talk about that first line of every shell script, the shebang line. If you know all about shebang lines and env, please skip_ahead to the last section.
Since the earliest versions of Unix, this first line is used to point to the executable that should be used to execute the script. Classic example:
#!/bin/sh
This signals two things:
#! is used as a magic number to determine the endianness.
- The whole script should be executed using
sh located in the /bin/ directory.
This worked without much problems in the past 20 years or so (at least I think so, since it hasn’t changed much since then). This is mostly because there weren’t much different options for script executors, mostly just shell variants (sh, bash, csh, etc.), and these are always installed in default locations.
The past couple of years has seen the rise of several different scripting/programming languages, such as Perl, Python, and Ruby. These also use the shebang line. However, unlike shells, a default location for the scripting language interpreters is not vital for a unix system. It will boot fine without any of them present. And when there is room for options, *nix distribution will make different choices.
What makes it problematic is that most shell script authors will assume that your system is a default, standard Linux install, where all scripting interpreters are installed in `/usr/local/bin/`. This works on their system, so it should work on everybody else’s system! Wrong!
There are lots of systems around that don’t do have the interpreters there, or if they do, they often have a more up to date version in some other directory. This seems to be a hard problem, but luckily there is env. env is located in /usr/bin/ and can act as a pointer for the shell to find the right interpreter, based on the configuration of the user executing the script.
And the great thing about env that it is always located in /usr/bin/, because a lot of scripts depend on it.
The sad thing is that not many script authors know or care about the existence of env. Which can be a real pain for OS X users, because the standard interpreters are pretty old and most use either Fink or DarwinPorts and these install the interpreters in /sw/local/bin/ or /opt/local/bin respectively.
So please, spread the word, remember this when you write your next script: always start your script with the line
#!/usr/bin/env <interpreter>
The only valid exception to this rule is when you really need to feed arguments to the interpreter. Perl is notorious for wanting arguments, and while FreeBSD’s env handles arguments just fine, most other versions of env unfortunately do not. So besides spreading the word about env, also put in a good word for FreeBSD’s version of env.