Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

If want to check if a process is running and start it if not. My script below is buggy and always says that a process is running. What is wrong?

$ ./check_n_run thisisnotrunning
./check_n_run: thisisnotrunning is already running

Here is the script:

$ cat check_n_run

#!/bin/sh

USAGE="usage: $0 processname"
if [ $# -ne 1 ] ; then
        echo "$USAGE" >&2
        exit 1
fi

ps ax | grep -v grep | grep $1> /dev/null
if [ $? -eq 1 ]
then
  echo "$1 not running"
  # start here      
else
  echo "$0: $1 is already running" >&2
fi

exit 0
share|improve this question
    
If you were to use ps|grep to exclude grep properly from the results the grep -v should be after the grep $1. However, the answers below are what you really need. (Even though I get 0 and 1 where you'd expect in tests in Bash on my system. But your test should be [ $? -ne 0 ].) –  Dennis Williamson Jul 18 '10 at 23:37

4 Answers 4

The problem in your script is that (with the shell you're using) in a pipeline, each command runs in a separate subshell, and none of their statuses is propagated to the parent process. So after command1 | command2, $? is always 0.

Even if you fixed it, your script is highly unreliable: it will match processes with a name that contains your process as a substring. Linux provides the pidof command that does exactly what you're trying to do.

However this is still not ideal, because there could be another process with the same name. It would be better to use a proper service supervisor, such as Debian/Ubuntu's start-stop-daemon, or an upstart service. lockfile (from procmail), mentioned by Wrikken, is also a possibility.

share|improve this answer

As long as ps / grep doesn't error out, $? whould be 0.


edit: according to Gilles (I have neither shell available a.t.m.):

in ksh/zsh, $? would be 1 if grep neither found a match nor errored out


I usually tend to use lockfile in the startup of those processes...

lockfile /path/to/lockfile && (do_something; rm -f /path/to/lockfile)

Although your script could be altered to:

procs=`ps ax | grep -v grep | grep -c $1`
if [ $procs -lt 1 ]
then
....
share|improve this answer
1  
With ash/bash/pdksh, $? will always be 0 in this script. With ksh/zsh, $? would be 1 if grep neither found a match nor errored out. –  Gilles Jul 18 '10 at 22:40
    
OK, I don't use those shells, edited the answer. –  Wrikken Jul 18 '10 at 23:30

Problem: if your system is anything like mine, the output of ps ax includes not only the process name, but the entire command line used to run it. So when you run

./check_n_run thisisnotrunning

the output of ps ax will literally include that line, so grep will always find a result for thisisnotrunning. That explains why your script always reports that the program is running.

To get around that, there are a few options. As Gilles mentioned, the best one is to use start-stop-daemon to start and stop your script. If that's not a possibility, you can use pidof to detect whether the given executable is running. And if for some reason that were not available, you could use

ps -C thisisnotrunning

which only prints processes with the given command name.

share|improve this answer
    
I assume that's why the OP used a grep -v grep Kludgy, but effective. –  Wrikken Jul 19 '10 at 8:23
    
But grep -v grep doesn't filter out the process that runs the shell script itself. –  David Z Jul 19 '10 at 22:32

I think you tried the hard way. I don't know what distribution you use, but try to see the path /var/run. It's a directory including the pid of every process.

Just try ls *something*. If something is return, then your process is running. Otherwise it's not.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.