Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
SCRIPT(7)	     BSD Miscellaneous Information Manual	     SCRIPT(7)

NAME
     script -- interpreter script execution

DESCRIPTION
     The system	is capable of treating a text file containing commands in-
     tended for	an interpreter,	such as	sh(1) or awk(1), as an executable pro-
     gram.

     An	"interpreter script" is	a file which has been set executable (see
     chmod(2)) and which has a first line of the form:

	   #! pathname [argument]

     The "#!" must appear as the first two characters of the file.  A space
     between the "#!" and pathname is optional.	 At most one argument may fol-
     low pathname, and the length of the entire	line is	limited	(see below).

     If	such a file is executed	(such as via the execve(2) system call), the
     interpreter specified by the pathname is executed by the system.  (The
     pathname is executed without regard to the	PATH variable, so in general
     pathname should be	an absolute path.)

     The arguments passed to the interpreter will be as	follows.  argv[0] will
     be	the path to the	interpreter itself, as specified on the	first line of
     the script.  If there is an argument following pathname on	the first line
     of	the script, it will be passed as argv[1].  The subsequent elements of
     argv will be the path to the interpreter script file itself (i.e. the
     original argv[0]) followed	by any further arguments passed	when execve(2)
     was invoked to execute the	script file.

     By	convention, it is expected that	an interpreter will open the script
     file passed as an argument	and process the	commands within	it.  Typical
     interpreters treat	`#' as a comment character, and	thus will ignore the
     initial line of the script	because	it begins "#!",	but there is no	re-
     quirement for this	per se.

     On	NetBSD,	the length of the "#!" line, excluding the "#!"	itself,	is
     limited to	PATH_MAX (as defined in	<limits.h>).  Other operating systems
     impose much smaller limits	on the length of the "#!" line (see below).

     Note that the interpreter may not itself be an interpreter	script.	 If
     pathname does not point to	an executable binary, execution	of the inter-
     preter script will	fail.

   Trampolines and Portable Scripts
     Different operating systems often have interpreters located in different
     locations,	and the	kernel executes	the passed interpreter without regard
     to	the setting of environment variables such as PATH.  This makes it
     somewhat challenging to set the "#!" line of a script so that it will run
     identically on different systems.

     Since the env(1) utility executes a command passed	to it on its command
     line, it is often used as a "trampoline" to render	scripts	portable.  If
     the leading line of a script reads
	   #! /usr/bin/env interp
     then the env(1) command will execute the "interp" command it finds	in its
     PATH, passing on to it all	subsequent arguments with which	it itself was
     called.  Since /usr/bin/env is found on almost all	POSIX style systems,
     this trick	is frequently exploited	by authors who need a script to	exe-
     cute without change on multiple systems.

   Historical Note: Scripts without "#!"
     Shell scripts predate the invention of the	"#!" convention, which is im-
     plemented in the kernel.  In the days of Version 7	AT&T UNIX, there was
     only one interpreter used on the system, /bin/sh, and the shell treated
     any file that failed to execute with an ENOEXEC error (see	intro(2)) as a
     shell script.

     Most shells (such as sh(1)) and certain other facilities (including
     execlp(3) and execvp(3) but not other types of exec(3) calls) still pass
     interpreter scripts that do not include the "#!" (and thus	fail to	exe-
     cute with ENOEXEC)	to /bin/sh.

     As	this behavior is implemented outside the kernel, there is no mechanism
     that forces it to be respected by all programs that execute other pro-
     grams.  It	is thus	not completely reliable.  It is	therefore important to
     always include
	   #!/bin/sh
     in	front of Bourne	shell scripts, and to treat the	traditional behavior
     as	obsolete.

EXAMPLES
     Suppose that an executable	binary exists in /bin/interp and that the file
     /tmp/script contains:

	   #!/bin/interp -arg

	   [...]

     and that /tmp/script is set mode 755.

     Executing

	   $ /tmp/script one two three

     at	the shell will result in /bin/interp being executed, receiving the
     following arguments in argv (numbered from	0):

	   "/bin/interp", "-arg", "/tmp/script", "one",	"two", "three"

   Portability Note: Multiple arguments
     The behavior of multiple arguments	on the "#!" line is highly non-porta-
     ble between different systems.  In	general, only one argument can be as-
     sumed to work consistently.

     Consider the following variation on the previous example.	Suppose	that
     an	executable binary exists in /bin/interp	and that the file /tmp/script
     contains:

	   #!/bin/interp -x -y

	   [...]

     and that /tmp/script is set mode 755.

     Executing

	   $ /tmp/script one two three

     at	the shell will result in /bin/interp being executed, receiving the
     following arguments in argv (numbered from	0):

	   "/bin/interp", "-x -y", "/tmp/script", "one", "two",	"three"

     Note that "-x -y" will be passed on NetBSD	as a single argument.

     Although most POSIX style operating systems will pass only	one argument,
     the behavior when multiple	arguments are included is not consistent be-
     tween platforms.  Some, such as current releases of NetBSD, will concate-
     nate multiple arguments into a single argument (as	above),	some will
     truncate them, and	at least one will pass them as multiple	arguments.

     The NetBSD	behavior is common but not universal.  Sun's Solaris would
     present the above argument	as "-x", dropping the "	-y" entirely.  Perhaps
     uniquely, recent versions of Apple's OS X will actually pass multiple ar-
     guments properly, i.e.:

	   "/bin/interp", "-x",	"-y", "/tmp/script", "one", "two", "three"

     The behavior of the system	in the face of multiple	arguments is thus not
     currently standardized, should not	be relied on, and may be changed in
     future releases.  In general, pass	at most	one argument, and do not rely
     on	multiple arguments being concatenated.

SEE ALSO
     awk(1), csh(1), ksh(1), sh(1), chmod(2), execve(2), intro(2), execlp(3),
     execvp(3),	fd(4), options(4), setuid(7)

STANDARDS
     The behavior of interpreter scripts is obliquely referred to, but never
     actually described	in, IEEE Std 1003.1-2004 ("POSIX.1").

     The behavior is partially (but not	completely) described in the System V
     Interface Definition, Fourth Edition ("SVID4").

     Although it has never been	formally standardized, the behavior described
     is	largely	portable across	POSIX style systems, with two significant ex-
     ceptions: the maximum length of the "#!" line, and	the behavior if	multi-
     ple arguments are passed.	Please be aware	that some operating systems
     limit the line to 32 or 64	characters, and	that (as described above) the
     behavior in the face of multiple arguments	is not consistent across sys-
     tems.

HISTORY
     The behavior of the kernel	when encountering scripts that start in	"#!"
     was not present in	Version	7 AT&T UNIX.  A	Usenet posting to net.unix by
     Guy Harris	on October 16, 1984 claims that	the idea for the "#!" behavior
     was first proposed	by Dennis Ritchie but that the first implementation
     was on BSD.

     Historical	manuals	(specifically the exec man page) indicate that the be-
     havior was	present	in 4BSD	at least as early as April, 1981.  Information
     on	precisely when it was first implemented, and in	which version of UNIX,
     is	solicited.

SECURITY CONSIDERATIONS
     Numerous security problems	are associated with setuid interpreter
     scripts.

     In	addition to the	fact that many interpreters (and scripts) are simply
     not designed to be	robust in a setuid context, a race condition exists
     between the moment	that the kernel	examines the interpreter script	file
     and the moment that the newly invoked interpreter opens the file itself.

     Because of	these security issues, NetBSD does not allow setuid inter-
     preter scripts by default.	 In order to turn on setuid interpreter
     scripts,
	   options SETUIDSCRIPTS
     must be set in the	configuration of the running kernel.  Setting this op-
     tion implies the FDSCRIPTS	option,	which causes the kernel	to open	the
     script file on behalf of the interpreter and pass it in argv as
     /dev/fd/[fdnum].  (See fd(4) for an explanation of	the /dev/fd/[fdnum]
     devices.)	This design avoids the race condition, at the cost of denying
     the interpreter the actual	name of	the script file.  See options(4) for
     more information.

     However, the FDSCRIPTS mechanism is not a cure-all	for security issues in
     setuid interpreters and scripts.  Subtle techniques can be	used to	sub-
     vert even seemingly well written scripts.	Scripts	executed by Bourne
     type shells can be	subverted in numerous ways, such as by setting the IFS
     variable before executing the script.  Other interpreters possess their
     own vulnerabilities.  Turning on SETUIDSCRIPTS is therefore very danger-
     ous, and should not be done lightly if at all.

BSD				  May 6, 2005				   BSD

NAME | DESCRIPTION | EXAMPLES | SEE ALSO | STANDARDS | HISTORY | SECURITY CONSIDERATIONS

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=script&sektion=7&manpath=NetBSD+6.0>

home | help