Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
'#!'-magic, details about the shebang mechanism
[go: Go Back, main page]

Bourne | Shells |  #!  | ash | find | ARG_MAX | echo | "$@" | $() vs ) | UUOC | IFS | - | ../Various | HOME
portability | permissions | tty defs | tty chars | using siginfo | nanosleep | line charset | locale


The '#!'-magic, details about the shebang mechanism on various Unix flavours

2006-03-07 (see recent changes)

Here you'll find


More reading:


Selected details:


Test results on various systems:

I used the following as program "showargs":

    #include <stdio.h>
    int main(int argc, char** argv) {
	int i;
	for (i=0; i<argc; i++)
	    fprintf(stdout, "argv[%d]: \"%s\"\n", i, argv[i]);
	return(0);
    } 

and a one line script named "invoker.sh" to call it, similar to this,

    #!/tmp/showargs -1 -2 -3 

to produce the following results (tried them myself, but i'd like to add your results from yet different systems).

Typically, a result from the above would look like this:

    argv[0]: "/tmp/showargs"
    argv[1]: "-1 -2 -3"
    argv[2]: "./invoker.sh"

... but the following table lists the variations. The meaning of the columns is explained below.

OS (arch) maximum
length of
#! line
cut-off (c),
error (err) or
ENOEXEC ()
[1]
only the
1st arg
passed on
each arg
in its own
argv[x]
handle #
like a
comment
argv[0]:
invoker,
instead of
interpreter
not full
path in
argv[0]
remove
trailing
white-
space
accept
inter-
preter
[2]
AIX 3.2.5 (rs6k) [3] 255/80 c [3]         [3]    
AIX 4.3.2 (rs6k) 256           X    
BSDi/OS 4.2 (i386) 4096 err   X   ? ? X  
EP/IX 2.2.1 (mips) 1024       ?        
FreeBSD 1.1- / 4.0-4.4 64     X - / X     X  
FreeBSD 4.5-4.x 128 err   X X     X  
FreeBSD 6.0 (alpha) 8192 c           X  
HP-UX A.08.07/B.09.03 32         X      
HP-UX B.10.10 [4] 128/80 c [4]       [4] [4] X  
HP-UX B.10.20-11.11 128             X  
IRIX 5.3/6.5 (mips) 256 err              
Linux 2.2.9-2.6.7 127 c         X X  
Minix 2.0.3-3.1.1 257     X       X X
MUNIX 3.1 (svr3.x, 68K) 32         X      
NetBSD 0.8-1.6Q / 1.6R- 64 / 1024                
OpenBSD 2.0-3.4 64                
OSF1 V4.0B-T5.1 1024           X    
OpenServer 5.0.6 [5] 256 err X            
SINIX 5.20 (MX300/NSC) 32                
SunOS 4.1.4 (SPARC) 32 c           X  
SunOS 5.x (SPARC) 1024   X         X  
Ultrix 4.5 (VAX3100/RISC) 32 / 80 c              
Unicos 9.0.2.2 (cray) 32                
UWIN (i386) 255 c     ?     X X

Meaning of the columns:

Footnotes in the table:

[1] If the #!-line is too long, at least three things can happen:
  • The line gets truncated
  • Due to a returned E2BIG (IRIX, SCO OpenServer) or ENAMETOOLONG ( FreeBSD, BSD/OS) you get something like "Arg list too long"/"Arg list or environment too large" or "File name too long", respectively.
  • You get ENOEXEC (which results in a silent failure in several shells).

[2] Most probably there isn't any Bell-Labs-derived Unix at all that accepts "nested" #!.
However, Minix and the UWIN environment (Unix Services for Windows) accept this.
Be careful not to confuse whether the kernel accepts an interpreted script in the shebang line or if your shell silently tries to take over if the kernel refused to do this. bash-1 always behaves so and bash-2 does so, if the #! mechanism was not present at compile time (non-unix systems today, though). Some other "modern" shells might behave similar.

[3] AIX 3: If the #!-line exceeds 255 characters, it gets cut down to exactly 80 characters--or the first argument, if this is shorter. If the #!-line was not too long, argv[0] is the basename of the interpreter, otherwise its absolute path.

[4] HP-UX 10.10: If the #!-line exceeds 128 characters, it gets cut down to exactly 80 characters--or the first argument, if this is shorter. If the #!-line was short enough, argv[0] contains the name of the invoking program (with relative path), otherwise the name of the invoked interpreter (with absolute path).

[5] John H. DuBois told me that #! was introduced in SCO UNIX 3.2v4.0, but was disabled by default; if you wanted to use it, it had to be enabled by setting hashplingenable in kernel/space.c ("hashpling" because it was implemented by programmers in Britain). It was apparently enabled by default in 3.2v4.2, but even then there were no #! scripts shipped with the OS as a customer might disable it. The first #! scripts (tcl) were shipped in 3.2v5.0 then.


And why shebang? In music, '#' means sharp. So just shorten '#!' to sharp-bang. Or it might be derived from "shell bang". All this probably under the influence of the american slang idiom "the whole shebang" (everything, the works, everything involved in what is under consideration).

See also the jargon dictionary or the Merriam-Websters for the slang idiom.

Sometimes it's also called hashbang, sha-bang/shabang, hashexclam or hashpling (british).


<http://www.in-ulm.de/~mascheck/various/shebang/>

2006-02-01, Sven Mascheck