6

I am trying to check if a process is running with the code below:

SERVICE="./yowsup/yowsup-cli"
RESULT=`ps aux | grep $SERVICE`

if [ "${RESULT:-null}" = null ]; then
    echo "not running"
else
    echo "running"
fi

But it keeps echoing it is running although it is not. I realized that the grep itself comes as a result and that is the issue.

How can I skip the grep and just check for the process?

8 Answers8

14

Use pgrep:

if pgrep "$SERVICE" >/dev/null 2>&1 ; then
    echo "$SERVICE is running"
fi

or:

if pgrep -f "/path/to/$SERVICE" >/dev/null 2>&1 ; then
    echo "$SERVICE is running"
fi

NOTE:

  • pgrep interprets its argument as a regular expression. As a result, paths containing regex characters will likely fail to match or produce false positives (e.g. pgrep -f /home/user/projects/c++/application/executable won't work as expected due to +). This issue can be worked around by escaping the characters in question (e.g. pgrep -f /home/user/projects/c\+\+/application/executable)

  • pgrep -f <pattern> matches the specified pattern against the whole command line of running processes. As a result, it will match paths appearing as arguments of other processes (e.g. run nano /usr/bin/sleep in one terminal and pgrep -f /usr/bin/sleep in another -> pgrep reports the pid of nano since it contains /usr/bin/sleep as an argument in its command line). To prevent these kind of false positives, prefix the pattern with a caret (^) to force pgrep to only match against the beginning of the command line (e.g. pgrep -f ^/usr/bin/sleep)

Fonic
  • 2,625
  • 23
  • 20
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • This is actually not that reliable as `pgrep` interprets the argument specified as a _pattern_. As a result, paths containing regex characters will fail to match or produce false positives, e.g. `pgrep -f "/home/user/projects/c++/application/executable"` won't work as expected. – Fonic Jul 01 '22 at 07:16
  • @Maxxim Good point, thanks for the input! ... I know that `grep` has the option `-F` for a fixed string search (no pattern), but pgrep apparently doesn't have this option. – hek2mgl Jul 25 '22 at 20:07
  • ps: awk could be used for a fixed string search. Like this: `ps ax -o pid,cmd | awk -v search='search_string' '{pid=$1;$1=""} index($0, search){print pid}'` ... In this example, `search_string` may contain any kind of special character. – hek2mgl Jul 25 '22 at 22:49
  • Upon further inspection, I'd say `pgrep -f` is actually not reliable at all and should probably be avoided altogether. Try the following: run `nano /usr/bin/sleep` in one terminal and `pgrep -f /usr/bin/sleep` in another -> `pgrep` will report the pid of `nano` since it contains `/usr/bin/sleep` in its command line. It seems `pgrep -f` blindly matches against the whole command line, including arguments. I'd say this disqualifies `pgrep -f` for this use case entirely. – Fonic Jul 29 '22 at 06:50
  • @Maxxim It seems you are right, I should remove `-f` from my answer. I will leave that to you if you want?, in the meanwhile your note keeps in sync with the answer. Thanks again, appreciated! – hek2mgl Jul 30 '22 at 22:10
  • I opted to add another note as there is a viable workaround. Also, I think it's better to keep a (partially) wrong answer and explain its pitfalls/limitations so others can learn from it. My guess is that if you were to remove it, someone else would probably repost it anyway as `pgrep`'s goofs are not very obvious (took me quite some time to figure it out). I removed the 'more reliable' remark though as that is not necessarily true now that we know more about it. – Fonic Aug 01 '22 at 08:00
7

For systems where pgrep isn't available you can use:

service="[.]/yowsup/yowsup-cli"

if ps aux | grep -q "$service"; then
    echo "not running"
else
    echo "running"
fi
  • [.] in will force grep to not list itself as it won't match [.] regex.
  • grep -q can be utilized to avoid command substitution step.
  • Prefer using lowercase variables in shell.
anubhava
  • 761,203
  • 64
  • 569
  • 643
4

The problem is that grep you call sometimes finds himself in a ps list, so it is good only when you check it interactively:

$ ps -ef | grep bash
...
myaut    19193  2332  0 17:28 pts/11   00:00:00 /bin/bash
myaut    19853 15963  0 19:10 pts/6    00:00:00 grep --color=auto bash

Easiest way to get it is to use pidof. It accepts both full path and executable name:

service="./yowsup/yowsup-cli" # or service="yowsup-cli"
if pidof "$service" >/dev/null; then
    echo "not running"
else
    echo "running"
fi

There is more powerful version of pidof -- pgrep.


However, if you start your program from a script, you may save it's PID to a file:

service="./yowsup/yowsup-cli"
pidfile="./yowsup/yowsup-cli.pid"
service &
pid=$!
echo $pid > $pidfile

And then check it with pgrep:

if pgrep -F "$pidfile" >/dev/null; then
    echo "not running"
else
    echo "running"
fi

This is common technique in /etc/init.d start scripts.

myaut
  • 11,174
  • 2
  • 30
  • 62
2

The following solution avoids issues with ps + grep, pgrep and pidof (see Advantages below):

# Check if process is running [$1: path to executable]
function is_process_running() {
    local path="$1" line
    while read -r line; do
        [[ "${line}" == "${path}" || "${line}" == "${path} "* ]] && return 0
    done < <(ps -e -o command=)
    return 1
}

is_process_running "./yowsup/yowsup-cli" && echo "running" || echo "not running"

Explanation:

  • ps -e -o command= list all processes, only output command line of each process, omit header line
  • while read -r line; do ... done < <(ps ...) process output produced by ps line by line
  • [[ "${line}" == "${path}" || "${line}" == "${path} "* ]] check if line matches path exactly -or- path + space + argument(s)

Advantages:

  • Works for paths containing regex special characters that would trip grep without option -F or pgrep, e.g. /home/user/projects/c++/application/executable (see NOTE in this answer for details)
  • Avoids issues with ps + grep / pgrep reporting false positives if path appears as argument of some other process (e.g. nano /usr/bin/sleep + pgrep -f /usr/bin/sleep -> falsely reports pid of nano process)
  • Avoids issues with pidof reporting false positives for processes that are run from PATH (e.g. sleep 60s & + pidof /tmp/sleep -> falsely reports pid of sleep process running from /usr/bin/sleep, regardless of whether /tmp/sleep actually exists or not)
Fonic
  • 2,625
  • 23
  • 20
1

I thought pidof was made for this.

function isrunning()
{
    pidof -s "$1" > /dev/null 2>&1
    status=$?
    if [[ "$status" -eq 0 ]]; then
        echo 1
    else
        echo 0
    fi
)
if [[ $(isrunning bash) -eq 1 ]]; then echo "bash is running"; fi
if [[ $(isrunning foo) -eq 1 ]]; then echo "foo is running"; fi
John Schmitt
  • 1,148
  • 17
  • 39
1
## bash

## function to check if a process is alive and running:

_isRunning() {
    ps -o comm= -C "$1" 2>/dev/null | grep -x "$1" >/dev/null 2>&1
}

## example 1: checking if "gedit" is running

if _isRunning gedit; then
    echo "gedit is running"
else
    echo "gedit is not running"
fi

## example 2: start lxpanel if it is not there

if ! _isRunning lxpanel; then
    lxpanel &
fi

## or

_isRunning lxpanel || (lxpanel &)

Note: pgrep -x lxpanel or pidof lxpanel still reports that lxpanel is running even when it is defunct (zombie); so to get alive-and-running process, we need to use ps and grep

Bach Lien
  • 1,030
  • 6
  • 7
0
current_pid="$$" # get current pid
# Looking for current pid. Don't save lines either grep or current_pid
isRunning=$(ps -fea | grep -i $current_pid | grep -v -e grep -e $current_pid)

# Check if this script is running
if [[ -n "$isRunning" ]]; then
    echo "This script is already running."
fi
Cristian
  • 548
  • 6
  • 8
0
SERVICE="./yowsup/yowsup-cli"
RESULT=`ps aux | grep $SERVICE|grep -v grep`

if [ "${RESULT:-null}" = null ]; then
    echo "not running"
else
    echo "running"
fi
Jumbo
  • 1
  • 1
  • 1
    Please share more details such that others can learn from it – Nico Haase Feb 19 '21 at 13:32
  • The community encourages adding explanations alongisde code, rather than purely code-based answers (see [here](https://meta.stackoverflow.com/questions/300837/what-comment-should-i-add-to-code-only-answers)). – costaparas Feb 20 '21 at 00:11