tags:

views:

62

answers:

3

Hi Folks,

Have people noticed that if you modify the source of a shell script, any instances that are currently running are liable to fail?

This in my opinion is very bad; it means that I have to make sure all instances of a script are stopped before I make changes. My preferred behavior would be that existing scripts continue running with old source code and that new instances use the new code (e.g. what happens for perl and python programs).

Do folks have any good workarounds for this behavior, other than pre-copying the shell script to a tempfile and running from that?

Thanks, /YGA

+2  A: 

Make sure the shell has to parse the whole file before executing any of it:

#!/bin/ksh
{
all the original script here
}

That does the trick.

Incidentally, with Perl (and I assume Python), the program parses the entire file before executing any of it, exactly as recommended here. Which is why you don't usually run into the problem with Perl or Python.

Jonathan Leffler
A: 

The desired behavior may not be possible, depending on complexity of the shell scripts that are involved.

If the full shell script is contained in a single source file, and that file is fully parsed before execution, then the shell script is generally safe from modifications to the copy on the disc during execution. Wrapping all the executable statements into a function (or series of functions) will generally achieve the goal you are after.

#!/bin/sh

doit() 
{
# Stuff goes here
}
# Main
doit

The difficulty comes when the shell script "includes" other shell scripts (e.g. ".", or "source"). If these includes are wrapped in a function, they are not parsed until that statement is reached in the flow of execution. This makes the shell script vulnerable to changes to that external code.

In addition, if the shell script runs any external program (e.g. shell script, compiled program, etc), that result is not captured until that point in the execution is reached (if ever).

#!/bin/sh

doit() 
{
    if [[some_condition]] ; then
         resultone=$(external_program)
    fi
}
# Main
doit
semiuseless
Your code should be considered pseudo code for `sh`.
Dennis Williamson
+2  A: 

Very slight addition to the other answers below:

#!/bin/sh
{
    # Your stuff goes here
    exit
}

The 'exit' at the end is important. Otherwise, the script file might still be accessed at the end to see if there are any more lines to interpret.

This question was later reposted here: http://stackoverflow.com/questions/2336977

Anonymous
Jonathan Leffler's solution is good, but wasn't working for me without the exit :-)
YGA