Dark Matter
Dark Matter

Reputation: 2311

Clarification in bash script

I have a bash script which I think is making a false assumption.

The bash script is as shown:

running()
{
if
    test -e .pid
then
    pid=`cat .pid`
    if
        ps -p $pid | grep -q $pid
    then
        return 0
    fi
fi
return 1
}

dd=`date +'%d'`
if
    running
then
    echo Still running PID: 
    cat .pid
else
    echo $$ > .pid
    echo Current PID: $$
    java -cp ./runLoad2.jar:$CLASSPATH runLoad.mainClass
fi

In my opinion the above bash shell script is making a false assumption while checking if the process id is still active or not.

Here while starting for the first time there is no .pid file so it creates the file and stores the pid in the .pid file.

The second time on wards it checks if the process id stored in the .pid file is active or not and if it is inactive or if the ps commad does not return any input it starts the java program.

But here after the first load is complete the pid is released back to os and when the shell script runs for the second time it uses the old pid which can be used by some other process and this is where I think its making a false assumption thinking that the stored process id always refers to this shell script.

I'm not sure if I'm correct. Can someone clarify.

Upvotes: 0

Views: 95

Answers (2)

John1024
John1024

Reputation: 113844

In the last else clause, you need to clean up after the java program finishes by deleting the .pid file:

else
    echo $$ > .pid
    echo Current PID: $$
    java -cp ./runLoad2.jar:$CLASSPATH runLoad.mainClass
    rm -f .pid
fi

Otherwise, as you surmise, the pid may be reused.

The above assumes that the java process does not fork or otherwise spawn background processes. If it does, you have other issues.

If there is a chance that your process terminates by ctrl-C or some such signal, then you need to trap the signal and put the clean up code in the trap. To do that, put the following near the beginning of the script:

MyExit() {
    rm -f .pid
    exit
}
trap MyExit EXIT

This causes the bash function MyExit to run when the script receives an EXIT signal.

MORE: Your program, modified minimally to add the exit trap, would be:

MyExit() {
    rm -f .pid
    exit
}

running()
{
if
    test -e .pid
then
    pid=`cat .pid`
    if
        ps -p $pid | grep -q $pid
    then
        return 0
    fi
fi
return 1
}

dd=`date +'%d'`
if
    running
then
    echo Still running PID: 
    cat .pid
else
    trap MyExit EXIT
    echo $$ > .pid
    echo Current PID: $$
    java -cp ./runLoad2.jar:$CLASSPATH runLoad.mainClass
fi

The definition of the MyExit function could go a variety of places as long as it is defined before the trap statement is executed. I put it at the top because it is commonly considered good style to have bash function definitions at the top.

The trap statement should to be placed strategically after the decision has been made to write the .pid file and before it has been written.

Upvotes: 1

anishsane
anishsane

Reputation: 20980

  1. Your java command may be internally forking & the parent among the 2 processes may be exiting, keeping the child running in the background.
    Hence the bash script exits, & PID becomes available to OS.

  2. Also, on another note, I would recommend adding exec before the java command, because (most likely,) you would want to monitor the java process rather than the parent (bash wrapper).
    By adding exec bash script PID will be inherited by the java process.

To verify speculation (1), try the exec method I described in (2). Check in ps -ef output, it the java process has indeed spawn a child process. If the parent process has exited, the child process should have ppid=1 (init)

Upvotes: 0

Related Questions