Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Can I make a bash command line that only runs a certain command if the process is not already running (in the background)?

How do I check*, if a command is already running?

(so I can add the next command with && in between them so the next one only executes if the first one is true).

*: test, determine, discover, find out

share|improve this question
1  
ps -ef | grep -v grep | grep "process_name" || run_command_here –  Rahul Patil Jun 10 '13 at 7:58
1  
@RahulPatil you can use just pgrep "process_name" instead of ps | grep | grep –  rush Jun 10 '13 at 9:09
    
hmm, I forget that.. :D –  Rahul Patil Jun 10 '13 at 9:19
1  
Why don't you use a "lock" file, and when you launch the second time, it will only launch when the lock file disappears. –  BitsOfNix Jun 10 '13 at 10:21

8 Answers 8

This can be tricky, because you can have separate instances of the same process that live independently. For example servers listening on different ports, or services running as different users. In order to distinguish between these instances, you need to assign each of them a unique tag. The tag is often a file, but it can be a local socket in the abstract namespace, a TCP port, etc. — any unique identifier will do. When the tag is a file, it can be a regular file containing a process ID (a pidfile), or a named pipe or socket that the file is listening on, etc. Ideally, the tag is a communication endpoint that allows clients to connect to that process.

Each of these different kinds of tags results in a different way of checking whether the instance you are seeking is up and running. For example, with a local file socket, try to connect to it, and start the process if there is no process listening on that socket. If the tag is a pidfile, check if there is a process with that process ID, but beware that this is fragile, since if the process has died, there may be an unrelated process that has reused its ID. Beware that if two clients try to reach the process in a short time frame, they might both find that the process doesn't exist and both attempt to start it; properly protecting from this race condition can be tricky.

It is easier to manage instances when they are all started by the same supervisor process, and that supervisor process detects when instances die and reacts accordingly. Many service monitoring programs that can do this.

If the program doesn't respond on a known communication endpoint and it isn't managed by a supervisor program, the poor man's tag is a pidfile: a file containing the process ID. When you start the process, write the pid to a file with a prearranged name. When you need the process to exist, read the pidfile and see if there is a process with that pid. When you kill the process, erase the pidfile. The most salient problem with an unsupervised pidfile is that if the process dies, its pid may be reused by some unrelated process. You should at least check the process name or the process executable to ensure that you are talking to the right process. Many unix variants have a pgrep command: pgrep SOMENAME lists the processes whose name contains SOMENAME as a substring, with additional options to limit to a particular user, to require an exact match, to change which of the several possible notions of “process name” is used, etc.

share|improve this answer

You could use this approach:

if [[ -z $(ps -C appname -opid=) ]]; then
    appname && secondapp
fi
share|improve this answer

I've used this technique from time to time:

$ pgrep <process name> || <process name>

Prior to pgrep it used to be done this way:

$ ps -eaf | grep -q <[p]rocess name> || <process name>

example

The bit with the [p] makes it so that the grep won't find itself as a result.

$ ps -eaf | grep -q [s]leep || sleep 10
share|improve this answer

Other options:

  • pgrep -xq processname
    • Only matches the first 15 characters in GNU/Linux
    • Doesn't include ancestors on OS X
  • ps -eo comm= | sed 's|.*/||' | grep -xq processname
    • Only matches the first 15 characters in GNU/Linux
    • sed 's|.*/||' removes dirname parts on OS X

In GNU/Linux ps -o comm truncates command names to 15 characters and pgrep and ps -C only match the first 15 characters.

ps -C (match command names) is not supported on OS X.

In OS X ps -o comm prints the absolute paths of commands and ps -co comm only prints command names. In GNU ps -o comm only prints command names and -c has a different meaning.

OS X's pgrep doesn't include ancestor processes (like bash, Terminal, or launchd) without -a. GNU's pgrep includes them by default and it doesn't support -a.

grep -x and pgrep -x don't imply -F, so use -Fx if the process name can contain regex characters.

share|improve this answer
    
-C is not available in my cygwin either :) –  naxa Jun 10 '13 at 15:04

With Bash

#!/usr/bin/env bash

[[ $# -eq 0 ]] && { echo -e "Usage:\t\t $0 <Process_name>  <Command here>"; exit 1;  }

ifnotrun(){
        local p=$1
        if ! ps -C "$1" -opid=
        then
                cmd=($@)
                echo ${cmd[@]:1}
        else
                echo "Process \"$p\" Already Running.."
                exit 1
        fi

}

ifnotrun $*

Note:- remove echo if output looks Ok.

share|improve this answer

I will explain the case where you run command in beckgreoud. The "$!" save the PID of the last background proccess. So, you can use it to find it in the the proccess tables following the answers above:

sleep 4 &
ps -ef | grep -w  $!  ...

The builtin command "jobs" - try this:

sleep 4&
J=`jobs`
while [ "$J" ]; do
        sleep 1
        jobs # This line flush the jobs' bufer.
        J=`jobs`
done

Regarding the "&&" option

Instead of && use the command wait. In the following example myproc2 will no run until myproc1 would finish:

myproc1 &
wait
myproc2
share|improve this answer

You can use it inside a script:

if [ `ps -ef | grep "script.sh" | grep -v grep | wc -l` -gt 1 ] ; then
echo "RUNNING...."
else
echo "NOT RUNNING..."
fi
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.