Operating System - HP-UX
1837086 Members
2552 Online
110112 Solutions
New Discussion

Test for process already running and backquotes

 
Graham Cameron_1
Honored Contributor

Test for process already running and backquotes

We have a suite of scripts which contain tests to make sure that another invocation is not already running, using the following syntax (taken from a script called mpr0200.sh):

if [ 1 != `ps -fu$USER | grep mpr0200.sh | grep -v grep |wc -l` ] ; then
# then mpr0200 is already running ABORT this run
echo
echo "****** ABORTING MPR0200 ********"
echo "****** ********"
echo "****** MPR0200 IS ALREADY RUNNING ********"
echo
exit 3
fi

The problem seems to be that the script will occasionally and unpredictably detect itself and abort, even when no other copy is running.

I suspect that this is a problem caused by the backquote operator. According to the man page for ksh, the use of backquotes may cause a separate process to be created, although the exact conditions when this happens are not clear to me.

So, assuming that the backquotes cause a separate process to be forked, and that the forked process is initially an exact clone of the parent until the actual test command is exec'd, I think that sometimes the test is finding the earlier (pre-exec'd) process.

Feasible? If so how do I fix ? Is there a better way for a script to check that another copy is not already running ?

I know that the use of backquotes is deprecated in favour of $(command), but this is a 3rd party application which I cannot change without invalidating my support contract.

Except I'll probably have to to fix this glitch.

Thanks in advance

-- Graham
Computers make it easier to do a lot of things, but most of the things they make it easier to do don't need to be done.
8 REPLIES 8
Simon Hargrave
Honored Contributor

Re: Test for process already running and backquotes

how about grep -v $PID in the clause, which should remove reference to both the current process, and any child forked processes (ie cause by your backquotes).

Clearly your wc -l expects "1" to return (ie the current process) so you'd need to change it to look for "0", but this should work i think.
Simon Hargrave
Honored Contributor

Re: Test for process already running and backquotes

Sorry when I say $PID I of course mean $$ (PID of current process)
Chris Wilshaw
Honored Contributor

Re: Test for process already running and backquotes

Rather than using ps, why not use a trigger file?

Get the script to check if a trigger files exists - if it does, the script is already running, and this run can abort, otherwise, create the trigger and continue;

#!/usr/bin/sh
TRIGGER=/tmp/trigger.txt

if [ -f $TRIGGER ]
then
echo "MPR0200 already running. Aborting"
exit 3
else
echo "MPR0200 not running. Creating trigger."
echo "MPR0200_NOW_RUNNING" > $TRIGGER
fi

Then just rm $TRIGGER once the rest of your script is complete.
Simon Hargrave
Honored Contributor

Re: Test for process already running and backquotes

trigger file is fine, however the script should be written to ensure that it carefully clears the trigger file. most notably if there's an error in execution, or it gets killed, it won't get to the last line of the code which clears the trigger.

a trap command can help this at the beginning of the script: -

if [ -f $TRIGGER ]
then
echo "MPR0200 already running. Aborting"
exit 3
else
echo "MPR0200 not running. Creating trigger."
echo "MPR0200_NOW_RUNNING" > $TRIGGER
trap "rm $TRIGGER" 0
fi

This will trap the exit of the script (whether killed, error, normal exit etc) and remove the trigger file.
Muthukumar_5
Honored Contributor

Re: Test for process already running and backquotes

When we are going to check the script called mpr0200.sh ( application / service ), using the process ID check by ps will not be good.

And more the format you used,
ps -fu$USER | grep mpr0200.sh | grep -v grep |wc -l

is not effective one.

You can avoid current process from being check as,

ps -fu $USER | grep -v grep | grep -v $$ | grep mpr02000.sh | wc -l

It is good to check with shell too as,
ps -fu $USER | grep -v grep | grep -v $$ | grep mpr02000.sh | grep sh | wc -l

Else,

Use a separate file as,

mpr02000.pid as like other services. Make an entry over there. If you are going to stop the service then remove entry there or make null.

Example script:
===============


if [[ ! -z /var/tmp/mpr02000.pid ]]
then
# then mpr0200 is already running ABORT this run
echo
echo "****** ABORTING MPR0200 ********"
echo "****** ********"
echo "****** MPR0200 IS ALREADY RUNNING ********"
fi

NOTE:

You have to make null the file while exiting from running instance.

Before Exiting make as,
> /var/tmp/mpr02000.pid

collect the process ID $$ and make an entry if there is not pid there out.

Easy to suggest when don't know about the problem!
Ian Dennison_1
Honored Contributor

Re: Test for process already running and backquotes

Graham,

Ahhh, my favourite piece of code, the infamous "am I running already?" script.

I have had endless arguments about this one, for using lock files, process tables, database queries and all that.

Here's the quick and dirty code that works 99.999% of the time (the 5 nines).

export PID=$$
export LNCOUNT=`ps -ef |grep [script name] |grep -v grep |awk -vpid=$PID '$2 != pid && $3 != pid '{print $0}' |wc -l`

Ignores all occurences of grep and all processes either being this process or spawned by this process.

The odd exception where this does not work is if there is a 3rd level ov shell spawning involved, which is very rare but I have seen it (SAP Automated Archives with Data Protector). In that case, then the complexity is so great that a C program should be written.

Share and Enjoy! Ian
Building a dumber user
Bill Hassell
Honored Contributor

Re: Test for process already running and backquotes

No need for any complexity at all. ps can do the entire job with 100% accuracy. Using grep with ps ALWAYS leads to problems such as you've seen. ps has a special option: -C which will look in the process table for an exact match of a process name--no grep needed. However, to enable this feature (and the -H and -o options), you need to turn on UNIX95, the XPG4 feature. Since UNIX95 can also affect other programs and libraries, it's best to set UNIX95 temporarily by putting it on the command line. Here is a demonstration:

(looking for POSIX shell processes: sh)
# ps -e | grep sh
4 ? 2:44 unhashdaemon
558 ? 0:00 sshd
12181 pts/td 0:00 sh
12233 pts/td 0:00 csh
12117 pts/tc 0:00 sh
11810 pts/tb 0:00 sh
12232 pts/td 0:00 ksh
11756 pts/ta 0:00 sh

(hummm, that's not what I wanted)

# UNIX95= ps -C sh
PID TTY TIME CMD
12117 pts/tc 00:00 -sh
11810 pts/tb 00:00 -sh
11756 pts/ta 00:00 -sh

Now that's much better. grep looks at everything, user names, pathnames, portions of process names. That's why unhashdaemon, ksh and csh were caught. We want only "sh" processes. BTW: the - in front of sh means that this process is a login shell.

So for your case:

UNIX95= ps -fC mpr0200.sh

Now you'll see exactly *all* of the mpr0200.sh processes and not: mpr0200.sh1 or mpr0200.share, etc. Note that -C finds all mpr0200.sh processes so now you can safely match based on username:

USER=bill
QTY=$(UNIX95= ps -fC mpr0200.sh | grep ^$USER | wc -l)

if [ $QTY -gt 0 ]
then
echo
echo "****** ABORTING MPR0200 ********"
echo "****** ********"
echo "****** mpr0200.sh quantity $QTY ALREADY RUNNING ********"
echo
exit 3
fi

The above version will also detect if more than 1 copy is running and report the quantity for that user.


Bill Hassell, sysadmin
Bill Hassell
Honored Contributor

Re: Test for process already running and backquotes

Note that while $() is preferred, it behaves the same way. Note that this technique (ps | grep something | grep -v grep ...) has been around for a very long time and has always had reliability issues such as the one you are seeing. Not all flavors of Unix may have a -C option but at least for HP-UX, you've got a solid solution.


Bill Hassell, sysadmin