3

Bash scripts start with the following line

#!/bin/bash
# Rest of script below
...

In bash the # character is the start of a comment, but #!/bin/bash is definitely not a comment, therefore it isn't bash but the kernel that interprets that statement.

So what exactly is that first line? Is it a specific language, or a special one-off case in the Linux kernel? Are there other commands or statements in this "language" that can be used when scripting?

Cory Klein
  • 18,911
  • 1
    It's called a shebang. http://en.wikipedia.org/wiki/Shebang_(Unix). When Unix loads this file into memory, the #! tells the exec function to make use of the executable interpreter on disk at the location, /bin/bash instead. – slm Nov 06 '13 at 00:08

3 Answers3

2

That is the shebang. Any program that accepts a filename as an argument can be specified there, and the script's filename is passed.

$ cat t.ex
#!/bin/cat
I have been cat!
$ ./t.ex
#!/bin/cat
I have been cat!
  • More fun is the shebang #!/usr/bin/tail --lines=+2, which will output the contents of the file without the shebang. – AJMansfield May 08 '15 at 22:54
2

Called the shebang, as Ignacio said, it's actually a bit of magic for the program loader in the OS. When a user attempts to execute a program, the loader reads the first two bytes of the program to learn {something}. If those two bytes are exactly # and !, the kernel reads everything from byte three to the first newline (in many systems it's a newline). It uses the string it finds as a pathname and then, if it can execute whatever is at the pathname, it does and feeds the rest of the first program file to that executable as input.

Those who want a more polished explanation could google "shebang kernel magic" and follow the link to the Wikipedia entry on the topic at http://en.wikipedia.org/wiki/Shebang_(Unix)

Mike Diehn
  • 1,008
2

The shebang (#!) is what's called a magic number. #! is the readable form of the 2 bytes 0x23 and 0x21. If you see the man page for the C function execve() the family of these exec functions what's picking up on these bytes and behaving differently when present.

excerpt from execve() man page

DESCRIPTION
       execve()  executes the program pointed to by filename.  filename must be 
       either a binary executable, or a script starting with a line of the form:

           #! interpreter [optional-arg]

       For details of the latter case, see "Interpreter scripts" below.

       argv is an array of argument strings passed to the new program.  envp is 
       an array of strings, conventionally of the  form key=value,  which are 
       passed as environment to the new program.  Both argv and envp must be 
       terminated by a null pointer. The argument vector and environment can be 
       accessed by the called program's main function, when it is defined as:

           int main(int argc, char *argv[], char *envp[])

       execve() does not return on success, and the text, data, bss, and stack 
       of the calling process are overwritten by that of the program loaded.

       If the current program is being ptraced, a SIGTRAP is sent to it after a
       successful execve().

The keen eye will notice that the form of the shebang takes only 2 arguments. One being the interpreter, the other an [optional-arg]. This is why you can't pass more than 1 argument, at least on Linux.

So commands like this won't work, the -f is ignored, I believe.

#!/usr/bin/foo -i -f

However, if the interpreter supports it, you can get around this limitation to a degree by doing it this way:

#!/usr/bin/foo -if
slm
  • 369,824