bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: bash problem with #!, rev 2


From: Bob Proulx
Subject: Re: bash problem with #!, rev 2
Date: Tue, 26 Jul 2005 23:32:49 -0600
User-agent: Mutt/1.5.9i

Dave Yost wrote:
> In other words, a program starting with
> 
>   #!/usr/local/bin/compileAndGo
> 
> should invoke /usr/local/bin/compileAndGo, and compileAndGo is a 
> program starting with
> 
>   #!/bin/bash

That is not a portable combination.  The #! needs to be a machine
executable and not a script.  You can't daisychain scripts.  Often I
have wanted that feature though.  It is a kernel limitation.

> The problem is that bash is executing the compileAndGo script as if 
> it were a bash script.
> 
> (Is this the first time anyone has used a shell script as a #! program?)

Not really.  Other people have tried it.  But legacy UNIX systems do
not support that configuration.  So most never tried it twice on those
platforms.  :-)

The #! interpreter must be an executable.  Quoting from the HP-UX
exec(2) man page for one example of a legacy system:

       When the script file is executed, the system executes the
       specified interpreter as an executable object file.

The Linux man page for execve says:

       filename must be either a binary executable, or a script
       starting with a line of the form "#! interpreter [arg]".  In
       the latter case, the interpreter must be a valid pathname for
       an executable which is not itself a script, which will be
       invoked as interpreter [arg] filename.

> Invoking a compileAndGo script works correctly in zsh, but not in 
> bash, sh, ksh, csh, or tcsh.

The zsh must be doing something extra special.  It must be
interpreting the #! line itself and passing it along as a daisychain.
And in fact in the zsh man page I see this:

       If execution fails because the file is not in executable
       format, and the file is not a directory, it is assumed to be a
       shell script.  /bin/sh is spawned to execute it.  If the
       program is a file beginning with `#!', the remainder of the
       first line specifies an interpreter for the program.  The shell
       will execute the specified interpreter on operating systems
       that do not handle this executable format in the kernel.

I can't speak for bash but the classic shell stat()'s the file and
finds it executable and so it exec()'s the file.  If that works then
great, stop there.  But if the exec of the file fails then it assumes
it must be a shell script since it is executable but not machine code.
The command line shell forks a copy of itself and reads the file as a
script.

The fact that it forks instead of forks and execs means that
unexported variables are active in the shell that interprets the
script.  That has caused some subtle problems over the years.  But
later POSIX shells have fixed that behavior.

       If a call to exec*() fails, sh is spawned to interpret the
       script file.  All nonexported aliases, functions, and named
       parameters are removed in this case.

[Aside: The csh looks at the first character of the file and if it is
a "#" then it forks and reads the file as a script.  But if it is not
a "#" then it invokes /bin/sh on the file because it must be a Bourne
syntax script instead of a csh script.]

So what you are seeing is normal behavior, depending upon your
kernel, the behavior of exec(2) on that system and the behavior of the
command line shell.

Bob




reply via email to

[Prev in Thread] Current Thread [Next in Thread]