Check if Mac process is running using Bash by process name

50,657

Solution 1

Parsing this:

ps aux | grep -v grep | grep -c [-i] $ProcessName

...is probably your best bet.

ps aux lists all the currently running processes including the Bash script itself which is parsed out by grep -v grep with advice from Jacob (in comments) and grep -c [-i] $ProcessName returns the optionally case-insensitive integer number of processes with integer return suggested by Sebastian.

Here's a short script that does what you're after:

#!/bin/bash
PROCESS=myapp
number=$(ps aux | grep -v grep | grep -ci $PROCESS)

if [ $number -gt 0 ]
    then
        echo Running;
fi

EDIT: I initially included a -i flag to grep to make it case insensitive; I did this because the example program I tried was python, which on Mac OS X runs as Python -- if you know your application's case exactly, the -i is not necessary.

The advantage of this approach is that it scales with you -- in the future, if you need to make sure, say, five instances of your application are running, you're already counting. The only caveat is if another application has your program's name in its command line, it might come up -- regular expressions to grep will resolve that issue, if you're crafty (and run into this).

Research the Darwin man pages for ps, grep, and wc.

Solution 2

A shorter solution:

if pgrep $PROCESS_NAME; then
    echo 'Running';
fi

Explanation:

pgrep exits with 0 if there is a process matching $PROCESS_NAME running, otherwise it exist with 1.
if checks the exit code of pgrep, and, as far as exit codes go, 0 is success.

Solution 3

Another way is to use (abuse?) the -d option of the killall command. The -d options won't actually kill the process, but instead print what will be done. It will also exit with status 0 if it finds a matching process, or 1 if it does not. Putting this together:

#!/bin/bash
`/usr/bin/killall -d "$1" &> /dev/null`
let "RUNNING = ! $?"     # this simply does a boolean 'not' on the return code
echo $RUNNING

To give credit where its due, I originally pulled this technique from a script in the iTunes installer.

Solution 4

This simple command will do the trick. The brackets around the process name prevent the grep command from showing in the process list. Note there is no space after the comma. There may be some portability issues as ps on some unix systems may require a dash before the options:

ps axo pid,command | grep "[S]kype"

The advantage is that you can use the results in an if statement like this:'

if [[ ! $(ps axo pid,command | grep "[i]Tunes.app") ]]; then
    open -a iTunes
fi

Or if you prefer this style:

[[ ! $(ps axo pid,command | grep "[S]kype") ]] && open -a Skype  || echo "Skype is up"

Another advantage is that you can get the pid by adding a pipe to awk '{print $1}'.

echo "iTunes pid: $(ps axo pid,command | grep "[i]Tunes.app" | awk '{print $1}')"

Solution 5

You can use either killall or kill, depending on if you are trying to find the task by PID or by name.

By Name:

if ! killall -s -0 $PROCESS_NAME >/dev/null 2>&1; then
  # Restart failed app, or do whatever you need to prepare for starting the app.
else
  at -f $0 +30seconds # If you don't have this on cron, you can use /usr/bin/at
fi

By PID:

if ! kill -0 $PID 2>/dev/null; then
  # Restart app, do the needful.
else
  at -f $0 +30seconds
fi

If you look at the OSX Manual you will see a different set of process management commands; since it's not the linux kernel, it makes sense that they would manage processes differently.

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/killall.1.html

A sample output from my terminal (striking out the user and hostname, of course):

user@localhost:~$ kill -0 782 # This was my old, stale SSH Agent.
bash: kill: (782) - No such process
user@localhost:~$ echo $?
1

user@localhost:~$ kill -0 813 # This is my new SSH agent, I only just created.
user@localhost:~$ echo $?
0

The return code from a kill -0 will always result in a safe way to check if the process is running, because -0 sends no signal that will ever be handled by an application. It won't kill the application, and "kill" is only called "kill" because it's usually used to stop an application.

When you look at the interfaces it uses in the source, you'll see that it's actually interacting with the process table directly (and not grepping a potentially loaded output from ps), and just sending a signal to an application. Some signals indicate the application should shutdown or stop, while other signals tell it to restart services, or re-read configuration, or re-open file descriptors to log files that have been recently rotated. There are a plethora of things that "kill" and "killall" can do that doesn't terminate the application, and it's used regularly to simply send a signal to the application.

Share:
50,657
Chris Redford
Author by

Chris Redford

PhD, Computer Science

Updated on September 27, 2020

Comments

  • Chris Redford
    Chris Redford over 3 years

    How do you check if a process on Mac OS X is running using the process's name in a Bash script?

    I am trying to write a Bash script that will restart a process if it has stopped but do nothing if it is still running.