How do I determine if a program is running when I start a shell and start that program if it is not already running?

Use pgrep like this:

if ! pgrep -u $USER top >/dev/null 2>&1; then
    exec top
fi

Explanation:

  • The pgrep utility exits with a zero exit code if the command can be found running. Therefore, negate the test.
  • Also restrict it to the current user with -u $USER, so that it doesn't for some reason pick up someone else's processes. $USER is a standard shell variable. If that for some reason isn't defined, try using $LOGNAME instead, and if that fails, use $( id -n -u ) (but at that point you have to ask yourself what's going on, because $LOGNAME is also a standard shell variable).
  • We don't need the output from pgrep, so redirect the standard output and error streams to /dev/null.

If top (or whatever) isn't found to be running, exec it to replace the shell, as per the OP's question.

This should be working in all sh-compatible shells.

EDIT: The pgrep implementation on BSD systems (OS X, OpenBSD, ...) has a -q option that makes it discard any output, but the pgrep on Linux apparently doesn't have this flag. On BSD systems, use this rather than the slightly ugly redirect to /dev/null.


If the program is always started from the shell and you have full control over it (ie. it is not hardcoded inside 3rd party program), then you can use some locking mechanism like lockfile or flock. For example by adding

flock -n /tmp/top -c top

to the .bashrc/.zshrc you will ensure that only first instance of the shell will run the top command (unless you kill it, then another one which will be started).

You may want to create a function in order to be able to start the command also by hand (not only when shell initialize):

mytop () { flock -n /tmp/$0 -c top; }

And just run mytop whenever you want.


Agreeing that pgrep is the way to go, there are some pitfalls. You need not use the -q option, since you can redirect the output of pgrep to eliminate that:

pgrep -U $USER top >/dev/null || exec top

The pitfalls lie in the fact that it is not a standard utility, so you have to keep in mind that it may not be portable. Here are a few manpage links, to help:

  • FreeBSD
  • Linux
  • Solaris

The USER environment variable is more well-established, but does not appear to be in POSIX's list for the shell (see 2.5.3 Shell Variables). Rather, it notes that USER is one of many variables known to be in use (see note in 8.1 Environment Variable Definition).

This runs top as yourself, of course. If you chose to make it run as root, then you could change the $USER to root and then run top using either sudo (preferred) or su. Neither is in POSIX (see list). The latter (su) is available everywhere on Unix-like systems, but sudo is generally preferred. So you would have

pgrep -U root top >/dev/null || exec sudo top

Unless you have configured sudo to not require a password, you will be prompted for a password when your shell starts top.