LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Bash: Check if a program is running (http://www.linuxquestions.org/questions/programming-9/bash-check-if-a-program-is-running-329962/)

naimslim89 06-03-2005 12:33 PM

Bash: Check if a program is running
 
Hello All,

I'm using Xorg 6.8.2 and the new composite extension. The visual effects are great, however it is still buggy.

One of the things that happen is that when I click (in GNOME) on Log Out, X crashes.

I've had to get around the problem by killing Xcompmgr (the composite manager) just before I log off. This gets tedious, having to do it every time I log out.

So I decided to make a custom application launcher, which runs a shell script when clicked on.

What I want the shell script to do is check if the program is already running or not, before it does anything. Basically, it'll act as a switch -- if xcompmgr is running, it'll kill it, and if it isn't running, it'll start it. What I need to know is how to get the script to check whether it's running or not.

The test command in bash scripting can only test certain things, most of them file based.

Here's my script as it stands:

Code:

#!bin/bash

if [ <my test goes here -- needs to return a true value if the process is running> ]
then killall xcompmgr
else exec xcompmgr -c -f
fi

Thanks for your time.

acid_kewpie 06-03-2005 01:43 PM

many ways, e.g.
Code:

if [ "$(pidof process_name)" ]
then
  # process was found
else
  # process not found
fi


naimslim89 06-04-2005 04:30 AM

Thank you very much, that was exactly what I was looking for!

waldeck 09-20-2009 10:10 AM

How to check if another instance of same script is running
 
Just to add my 5 cents to this discussion, if you want to check whether another instance of the same script is running you might want to try this:

Code:

if pidof -x $(basename $0) > /dev/null; then
  for p in $(pidof -x $(basename $0)); do
    if [ $p -ne $$ ]; then
      echo "Script $0 is already running: exiting"
      exit
    fi
  done
fi


Gimlic 02-13-2010 09:22 PM

I'm not sure what the difference is between pidof and pgrep, but I use the latter.

Code:

if [ -z "$(pgrep foo)" ]
  then
    # foo is not running
  else
    # foo is running
fi


penguen 12-24-2011 05:48 PM

The difference I see between pidof and pgrep is:

1-) pgrep greps the given process name where as pidof exactly matches the process name. ie pidof may not find processes name /bin/bash but pgrep will find all processes containing bash key.
2-) pidof separator is blank space while pgrep separator is newline.

jv2112 12-27-2011 06:36 AM

If you just want to kill the system....

:twocents:

Code:


#! /bin/bash/

shutdown -h now .... Goodbye $USER

exit 0


Stainy 05-04-2012 05:38 AM

also
 
Hi guys...

I would like to use a script like the one in this thread for checking on whether a process is running or not.
My situation is a tiny bit more complex.

I have a file generated that holds all the pids that I want to monitor.

How can I check on all these process`s to check whether one goes down or not? using the script in this thread??

anyone have any ideas?

Darren

jv2112 05-04-2012 01:49 PM

Not tested...

Code:

#! /bin/bash
check_it ()
{
wc -l file w/ PID > List
sleep 10

wc -l file w/ PID >Check

if [[ $(wc -l Check) -lt $(wc -l List) ]]
then
echo "Process Ended"
else
echo "No Issue"
fi

}


while [1] then check_it

exit


Stainy 05-08-2012 08:14 AM

Quote:

Originally Posted by jv2112 (Post 4670511)
Not tested...

Code:

#! /bin/bash
check_it ()
{
wc -l file w/ PID > List
sleep 10

wc -l file w/ PID >Check

if [[ $(wc -l Check) -lt $(wc -l List) ]]
then
echo "Process Ended"
else
echo "No Issue"
fi

}


while [1] then check_it

exit


Hmmm it does bum out on the 'while' saying not matched...

I take it there`s no differences with korn shell?

also this is my understanding wc -l <pathtofile> > List?


Darren

Nominal Animal 05-08-2012 09:28 AM

If you have a list of process IDs in file pidlist, first read it into a variable. For illustration, I'll use sed to edit out any non-PIDs, and read them into a space-separated string.
Code:

PIDS="$(sed -ne 's|^[\t\v\f ]*\([0-9]\+\)[\t\v\f ]*$|\1|p' pidlist | tr -s '[[:space:][:cntrl:]]' ' ')"
You might wish to use [ -n "$PIDS" ] at this point to verify there is at least one PID in PIDS.

Next, use ps to list the PIDs of still existing processes. Try to do it using a single command, because the ps command overhead is quite large. Only calling it once will be significantly faster than calling it for each PID separately.
Code:

ALIVE=" $(ps -o pid= -p "${PIDS[*]}" | tr -s '[[:space:][:cntrl:]]' ' ') "
Note that this one will have a space before and after every PID, including at the start and end of the string. This way, in Bash, you can use [ "$ALIVE" != "${ALIVE/ $PID /}" ] to test if PID is listed in ALIVE.

The only thing left to do is to check which PIDs from PIDS are listed in ALIVE.
Code:

for PID in $PIDS ; do
    if [ "$ALIVE" != "${ALIVE/ $PID /}" ]; then
        echo "Process $PID is still alive."
    else
        echo "Process $PID has died."
    fi
done

If you just want arrays of the PIDs that are still running or have died, you can rewrite the loop as
Code:

RUNNING=()
DIED=()
for PID in $PIDS ; do
    if [ "$ALIVE" != "${ALIVE/ $PID /}" ]; then
        RUNNING[${#RUNNING[@]}]=$PID
    else
        DIED[${#DIED[@]}]=$PID
    fi
done
# There are ${#RUNNING[@]} processes still running: ${RUNNING[@]}
# ${#DIED[@]} of the processes are gone: ${DIED[@]}

There is however a serious flaw in the overall logic, that should be fixed:
Because PIDs are reused eventually, the new PID could be a totally unrelated process!

To counter that, if all the processes run the same command, you could use
Code:

ALIVE=" $(ps -o pid= -C command | tr -s '[[:space:][:cntrl:]]' ' ') "
instead. This one lists all the PIDs for processes whose executable name is command. Or, if there are a few different names, use -C "cmd1 cmd2 .. cmdN" instead.
This way only existing processes running that command or those commands are considered.

There are other approaches, too. A typical one is to check that the still alive processes are in the right session or process group. I'd personally pick the approach depending on exactly what the processes are running, and how they are related. For typical servers, checking the executable name or process group is common, and those you can do by adjusting the parameters to the ALIVE ps command; instead of limiting to the set of PIDs in PIDS, look for all acceptable processes, and let the loop handle the limiting to the original set. See the man 1 ps manpage for details.

Stainy 05-08-2012 11:48 AM

Hi...

thanks so much for replying...

I`m fairly new to scripting...so I`m still trying to digest half of this ;)

but I`m getting an error

ps: 0509-048 Flag -p was used with invalid list.
I`m guessing in korn shell it doesn`t like the p flag with the commands I`ve passed to it..

also this list of pids is static all through the day and it changes the following day.. so I can schedule this script to run during trading hours, stop and then run again the following day.. shouldn`t be a problem I think..

Darren



Quote:

Originally Posted by Nominal Animal (Post 4673376)
If you have a list of process IDs in file pidlist, first read it into a variable. For illustration, I'll use sed to edit out any non-PIDs, and read them into a space-separated string.
Code:

PIDS="$(sed -ne 's|^[\t\v\f ]*\([0-9]\+\)[\t\v\f ]*$|\1|p' pidlist | tr -s '[[:space:][:cntrl:]]' ' ')"
You might wish to use [ -n "$PIDS" ] at this point to verify there is at least one PID in PIDS.

Next, use ps to list the PIDs of still existing processes. Try to do it using a single command, because the ps command overhead is quite large. Only calling it once will be significantly faster than calling it for each PID separately.
Code:

ALIVE=" $(ps -o pid= -p "${PIDS[*]}" | tr -s '[[:space:][:cntrl:]]' ' ') "
Note that this one will have a space before and after every PID, including at the start and end of the string. This way, in Bash, you can use [ "$ALIVE" != "${ALIVE/ $PID /}" ] to test if PID is listed in ALIVE.

The only thing left to do is to check which PIDs from PIDS are listed in ALIVE.
Code:

for PID in $PIDS ; do
    if [ "$ALIVE" != "${ALIVE/ $PID /}" ]; then
        echo "Process $PID is still alive."
    else
        echo "Process $PID has died."
    fi
done

If you just want arrays of the PIDs that are still running or have died, you can rewrite the loop as
Code:

RUNNING=()
DIED=()
for PID in $PIDS ; do
    if [ "$ALIVE" != "${ALIVE/ $PID /}" ]; then
        RUNNING[${#RUNNING[@]}]=$PID
    else
        DIED[${#DIED[@]}]=$PID
    fi
done
# There are ${#RUNNING[@]} processes still running: ${RUNNING[@]}
# ${#DIED[@]} of the processes are gone: ${DIED[@]}

There is however a serious flaw in the overall logic, that should be fixed:
Because PIDs are reused eventually, the new PID could be a totally unrelated process!

To counter that, if all the processes run the same command, you could use
Code:

ALIVE=" $(ps -o pid= -C command | tr -s '[[:space:][:cntrl:]]' ' ') "
instead. This one lists all the PIDs for processes whose executable name is command. Or, if there are a few different names, use -C "cmd1 cmd2 .. cmdN" instead.
This way only existing processes running that command or those commands are considered.

There are other approaches, too. A typical one is to check that the still alive processes are in the right session or process group. I'd personally pick the approach depending on exactly what the processes are running, and how they are related. For typical servers, checking the executable name or process group is common, and those you can do by adjusting the parameters to the ALIVE ps command; instead of limiting to the set of PIDs in PIDS, look for all acceptable processes, and let the loop handle the limiting to the original set. See the man 1 ps manpage for details.


Nominal Animal 05-08-2012 11:24 PM

Quote:

Originally Posted by Stainy (Post 4673507)
ps: 0509-048 Flag -p was used with invalid list.

Are you running on AIX?

Try comma-separated lists:
Code:

PIDS="`tr -cd '0-9\r\n' < pidfile | tr -s '[\n\r ]' ','`"
PIDS="${PIDS//,,/,}"
PIDS="${PIDS##,}"
PIDS="${PIDS%%,}"


# If you know the executables, use
ALIVE=",`ps -o pid= -C 'cmd1,cmd2,...,cmdN' | tr -s '[\t\n\v\f\r ]' ','`,"
# otherwise, use
ALIVE=",`ps -o pid= -p $PIDS | tr -s '[\t\n\v\f\r ]' ','`,"


for PID in ${PIDS//,/ } ; do
    if [ "$ALIVE" != "${ALIVE/,$PID,/}" ]; then
        echo "$PID still running"
    else
        echo "$PID has exited"
    fi
done

Note that if you set IFS="," then the for loop is written for PID in $PIDS ; do .


All times are GMT -5. The time now is 07:31 AM.