4

I infrequently have to write bash scripts for various unrelated purposes and while I usually have a good idea what commands I want in the script, I often have no idea what header to use or why I'm using one when I do find it. For example(s):

  • Standard shell script:
    • #!/bin/bash
  • Python:
    • #!/usr/bin/env python

Scripts seem to work fine without headers but if headers are the standard, there's a reason for them and they shouldn't be ignored. If it has an effect, then it's a valuable tool that could be used to accomplish more.

Minimally, I'd like to know what headers to use with MySQL scripts and what the headers do on Standard, Python, and MySQL scripts. Ideally, I'd like a generic list of headers or an understanding of how to create a header based on what program is being used.

Still.Tony
  • 1,428
  • 12
  • 34
  • http://stackoverflow.com/questions/2429511/why-do-people-write-usr-bin-env-python-on-the-first-line-of-a-python-script – anubhava Feb 12 '14 at 15:43

2 Answers2

7

How the Kernel Executes Things

Simplified (a bit), there are two ways the kernel in a POSIX system knows how to execute a program. One, if the program is in a binary format the kernel understands (such as ELF), the kernel can execute it "directly" (more detail out of scope). If the program is a text file starting with a shebang, such as

#!/usr/bin/somebinary -arg

or what-have-you, the kernel actually executes the command as if it had been directed to execute:

/usr/bin/somebinary -arg "$0"

where $0 here is the name of the script file you just tried to execute. (So you can immediately tell why so many scripting languages use # as a comment-starter – it means they don't have to treat the shebang as special.)

PATH and the env command

The kernel does not look at the PATH environment variable to determine which executable you're talking about, so if you are distributing a python script to systems that may have multiple versions of python installed, you can't guarantee that there will be a

#!/usr/bin/python

env, however, is POSIX, so you can count on it existing, and it will look up python in PATH. Thus,

#!/usr/bin/env python

will execute the script with the first python found in your PATH.

BASH, SH and Special Meanings for Invocation

Some programs have special semantics for how they're invoked. In particular, on many systems /bin/sh is a symlink to another shell, such as /bin/bash. While bash does not contain a perfectly POSIXLY_STRICT implementation of sh, when it is invoked as /bin/sh it is stricter than it would be if invoked as plain-old-bash.

MySQL and arg limitations

The shebang line can be length limited and technically, it can only support one argument, so mysql is a bit tricky – you can't expect to pass a username and database name to a mysql script.

#!/usr/bin/env mysql
use mydb;
select * from mytbl;

Will fail because the kernel will try mysql "$0". Even if you have your credentials in a .my.cnf file, mysql itself will try to treat "$0" as a database name. Likewise:

#!/usr/bin/mysql -e
use mydb;
select * from mytbl;

will fail because again, "$0" is not a table name (you hope).

There does not seem to be an appropriate syntax for directly executing a mysql script this way. Your best bet is to pipe the sql commands to mysql directly:

mysql < my_sql_commands
kojiro
  • 67,745
  • 16
  • 115
  • 177
4

http://mywiki.wooledge.org/BashGuide/Practices#Choose_Your_Shell

When the first line of a script starts with #!, that's what's called a "shebang". When that script is run as an executable, the operating system uses that line to determine how to run the script -- that is to say, to find the program with which the script should be executed.

It's incorrect that "scripts work fine without headers" -- if you don't have a shebang line, you can't be invoked using the execve() call, which means that many (most?) programs won't be able to execute your script. Sometimes invocation from a shell will try to use that shell itself in the absence of a shebang, but you can't trust that to be the case.

(There's an exception to that -- if someone starts your script by running sh yourscript or bash yourscript, the shebang line isn't read at all, and the script they chose is used; however, running scripts this way is a bad practice, as the author typically knows better than the user what the correct interpreter is).

In short:

  • If you want to use modern features, and you want the user to be able to override the shell version in use by putting a different release of bash earlier in their path, use #!/usr/bin/env bash
  • If you want to use modern features and ensure that you always run with the system shell, use #!/bin/bash
  • If you're going to write your script to strictly conform with POSIX sh, use #!/bin/sh

There's not a limited list of shebang lines we can give you, since any native executable (non-script program) can be used as a script interpreter, and thus be placed in a shebang. If you created a file called myscript with #!/usr/bin/env yourprogram, gave it executable permissions, and ran ./myscript foo bar, this would result in /usr/bin/env yourprogram myscript foo bar being invoked; yourprogram would be run by /usr/bin/env (after a PATH lookup), and would be responsible for knowing what to do with myscript and its arguments.

For an extremely detailed history of shebang lines and how they work across systems both modern and ancient, see http://www.in-ulm.de/~mascheck/various/shebang/

Charles Duffy
  • 235,655
  • 34
  • 305
  • 356
  • *The author typically knows better than the user…* authors who put bashisms in `/bin/sh` scripts notwithstanding. :) – kojiro Feb 12 '14 at 16:14