Check if a program in a specific path is running - linux

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?

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)

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.

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.

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)

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

## 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

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

SERVICE="./yowsup/yowsup-cli"
RESULT=`ps aux | grep $SERVICE|grep -v grep`
if [ "${RESULT:-null}" = null ]; then
echo "not running"
else
echo "running"
fi

Related

Why is my script telling me there's a process running when it's actually not?

func () {
local arrayOfParams=$#
local CMD="ps aux | grep -v grep"
for item in ${arrayOfParams[#]};
do
local CMD="$CMD | grep -e $item"
done
echo "Current process PID : $$"
echo "`date`: CMD is -> $CMD"
local isProcRunning=`eval ${CMD}`
if [[ 0 -eq `echo "$isProcRunning" | wc -l` ]];
then
echo "`date`: Following process is running: "
echo "$isProcRunning"
echo ""
if [[ "$FORCE_RUN" == true ]];
then
echo "`date`: User forced the run of current process ..."
# we extract the PIDs of proces mathcing our search criteria
PIDS=(`echo $isProcRunning | awk '{print \$2}'`)
for PID in "${PIDS[#]}";
do
# we extract the command running on said PID so that we know what we kill
local PIDCMD=`ps -o cmd -p ${PID} --no-headers`
echo "`date`: Killing PID: $PID with CMD -> $PIDCMD"
kill -9 $PID
done
else
echo "`date`: Current process will exit!!!"
fi
exit 0
fi
}
The above code is meant to check if current process is already running .
I use ps -ef and grep based on some params which should be found under CMD
I remove the line coresponding to the current PID and then I expect the wc -l to return 0, but it's returning 1.
I run that line outside of the script and I get 0 indeed.
Any idea why this is happening ?

Shell script to find the process state while excluding 'ps grep command'

can someone guide me writing shell script to find if the process is active or not? I have to exclude my own grep process filtering from ps command. I want to pass the process as a parameter,
script: (this is currently catching my own process)
#!/bin/sh
SERVICE=$1
echo $1
if ps ax | grep $SERVICE > /dev/null
then
echo "ok"
else
echo "not ok"
fi
example input tried: (though the process is dead I'm getting status as "ok")
./processchecker.sh '/usr/sbin/mysqld'
./processchecker.sh '[/usr/sbin/]mysqld' (i tried using square brackets using online suggestions but failed)
Please help.
You can use pgrep as well - which is a little more efficient:
#!/bin/sh
service=$1
status=0
if [ ! -z "$service" ]; then
pgrep "$service" >/dev/null; status=$?
if [ "$status" -eq 0 ]; then
echo "ok"
else
echo "not ok"
fi
fi
exit "$status"
It's better to have an appropriate exit value as well.
What you have is close, but you want to save the status of the grep command (via $?) and then if/else off of that value.
#!/bin/sh
SERVICE=$1
echo $1
ps ax | grep $SERVICE | grep -v ${0} > /dev/null
status=${?}
if [ "${status}" = "0" ]; then
echo "ok"
else
echo "not ok"
fi

Displayining multiple bash output horizontally

I have 4 important services running on my machine which I want to see them all the time. I have this simple bash script running as bash profile.
echo
PROC="nginx mysql php-fpm pptpd"
for p in $PROC
do
ps cax | grep $p > /dev/null
if [ $? -eq 0 ]; then
echo -e "\e[92m$p running\e[0m"
else
echo -e "\e[101m$p IS NOT RUNNING \e[0m"
fi
done
echo
The out put of this script is:
nginx running
mysql running
php-fpm running
pptpd running
How can I make it like this?
nginx running - mysql running - php-fpm running - pptpd running
Build the status lines first into an array, and then print the array:
status=()
for p in $PROC
do
if ps cax | grep -q $p; then
status+=( " \e[92m$p running\e[0m " )
else
status+=( " \e[101m$p IS NOT RUNNING \e[0m " )
fi
done
(IFS=-; echo -e "${status[*]}")
${status[*]} expands to every element in the array joined by the first character of IFS, which I set to - earlier. Note that I used a subshell (IFS=-; echo ...), so that changing IFS doesn't affect the rest of the script.
Other notes:
ps cax | grep $p > /dev/null
if [ $? -eq 0 ]; then
Can be combined to:
if ps cax | grep -q $p; then
Which is much more concise and readable. You could also consider using pgrep instead.
Use printf or add the -n flag to echo.
POSIX Compliant Refactor without ProcTools
#!/bin/sh
showstatus() {
echo
while [ "$1" ]; do
if ps cax | grep -qF "$1"; then
msg='\e[92m%s running\e[0m'
else
msg='\e[101m%s IS NOT RUNNING \e[0m'
fi
printf "$msg" "$1"
shift
[ "$1" ] && printf ' - '
done
echo
}
showstatus nginx mysql php-fpm pptpd
POSIX Compliant Refactor with ProcTools
#!/bin/sh
showstatus() {
echo
while [ "$1" ]; do
if pkill -0 "$1"; then
msg='\e[92m%s running\e[0m'
else
msg='\e[101m%s IS NOT RUNNING \e[0m'
fi
printf "$msg" "$1"
shift
[ "$1" ] && printf ' - '
done
echo
}
showstatus nginx mysql php-fpm pptpd

I am puzzled with the differences between "sh xxx.sh" and "./xxx.sh" for running a shell script

Here, I have a shell script named load.sh.
It start my program named "demo" with supervise,
When I run it with sh load.sh start | stop, it works well.
However, when I run it with ./load.sh start | stop, it works bad. the demo is frequently started(and exit) by the supervise.
What's the problem of the two ways of running the shell script?
and is there any problem(bug) in the script cause the supervise frequently restart the demo?
Thanks a lot!
#!/bin/bash
cd `dirname $0` || exit
mkdir -p status/demo
dir_name=`pwd`
STR_LIB=${dir_name}/lib
if [ -z "${LD_LIBRARY_PATH}" ]; then
export LD_LIBRARY_PATH="${STR_LIB}"
else
export LD_LIBRARY_PATH="${STR_LIB}:${LD_LIBRARY_PATH}"
fi
start() {
sleep 1
bin/supervise.demo -u status/demo bin/demo >/dev/null 2>&1 &
}
stop() {
if [ -f status/demo/lock ]; then
supervise_demo_pid=`/sbin/fuser status/demo/lock`
`ps -ef | grep "$supervise_demo_pid" | grep "supervise.demo" | grep -v grep > /dev/null 2>&1`
if [ $? -eq 0 ] && [ "$supervise_demo_pid" != "" ] ; then
echo "kill supervise.demo process:"${supervise_demo_pid}
kill -9 $supervise_demo_pid
fi
fi
if [ -f status/demo/status ]; then
demo_pid=`od -An -j16 -N2 -tu2 status/demo/status`
`ps -ef | grep "$demo_pid" | grep "demo" | grep -v grep > /dev/null 2>&1`
if [ $? -eq 0 ]; then
echo "kill demo process:"${demo_pid}
kill -9 $demo_pid
fi
fi
}
case "$1" in
start)
stop
start
echo "Done!"
;;
stop)
stop
echo "Done!"
;;
*)
echo "Usage: $0 {start|stop}"
;;
esac
sh script.sh runs the script in sh, while running it as ./script.sh uses whatever is specified on its first "shebang" line - /bin/bash in this case.
sh and /bin/bash might be different shells, so they interpret the script differently. What sh is depends on your distribution, $PATH, aliases etc.
When you run your script via ./load.sh start | stop it runs with processor that is specified in shebang. In your case it is bash:
#!/bin/bash
What about sh load.sh start | stop. In Ubuntu (by default) sh is actually just a link and in points to dash.
To check it:
$ which sh
/bin/sh
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 16 00:54 /bin/sh -> dash
sh foo will search $path for an executable foo
sh ./foo demands execution from the $cwd
both
foo and ./foo run via the shebang as noted herein
all forms will invoke foo with the perms of the specific file referenced, including suid,guid

Functionality of a start-stop-restart shell script

I am a shell scripting newbie trying to understand some code, but there are some lines that are too complexe for me. The piece of code I'm talking about can be found here: https://gist.github.com/447191
It's purpose is to start, stop and restart a server. That's pretty standard stuff, so it's worth taking some time to understand it. I commented those lines where I am unsure about the meaning or that I completely don't understand, hoping that somone could give me some explanation.
#!/bin/bash
#
BASE=/tmp
PID=$BASE/app.pid
LOG=$BASE/app.log
ERROR=$BASE/app-error.log
PORT=11211
LISTEN_IP='0.0.0.0'
MEM_SIZE=4
CMD='memcached'
# Does this mean, that the COMMAND variable can adopt different values, depending on
# what is entered as parameter? "memcached" is chosen by default, port, ip address and
# memory size are options, but what is -v?
COMMAND="$CMD -p $PORT -l $LISTEN_IP -m $MEM_SIZE -v"
USR=user
status() {
echo
echo "==== Status"
if [ -f $PID ]
then
echo
echo "Pid file: $( cat $PID ) [$PID]"
echo
# ps -ef: Display uid, pid, parent pid, recent CPU usage, process start time,
# controling tty, elapsed CPU usage, and the associated command of all other processes
# that are owned by other users.
# The rest of this line I don't understand, especially grep -v grep
ps -ef | grep -v grep | grep $( cat $PID )
else
echo
echo "No Pid file"
fi
}
start() {
if [ -f $PID ]
then
echo
echo "Already started. PID: [$( cat $PID )]"
else
echo "==== Start"
# Lock file that indicates that no 2nd instance should be started
touch $PID
# COMMAND is called as background process and ignores SIGHUP signal, writes it's
# output to the LOG file.
if nohup $COMMAND >>$LOG 2>&1 &
# The pid of the last background is saved in the PID file
then echo $! >$PID
echo "Done."
echo "$(date '+%Y-%m-%d %X'): START" >>$LOG
else echo "Error... "
/bin/rm $PID
fi
fi
}
# I don't understand this function :-(
kill_cmd() {
SIGNAL=""; MSG="Killing "
while true
do
LIST=`ps -ef | grep -v grep | grep $CMD | grep -w $USR | awk '{print $2}'`
if [ "$LIST" ]
then
echo; echo "$MSG $LIST" ; echo
echo $LIST | xargs kill $SIGNAL
# Why this sleep command?
sleep 2
SIGNAL="-9" ; MSG="Killing $SIGNAL"
if [ -f $PID ]
then
/bin/rm $PID
fi
else
echo; echo "All killed..." ; echo
break
fi
done
}
stop() {
echo "==== Stop"
if [ -f $PID ]
then
if kill $( cat $PID )
then echo "Done."
echo "$(date '+%Y-%m-%d %X'): STOP" >>$LOG
fi
/bin/rm $PID
kill_cmd
else
echo "No pid file. Already stopped?"
fi
}
case "$1" in
'start')
start
;;
'stop')
stop
;;
'restart')
stop ; echo "Sleeping..."; sleep 1 ;
start
;;
'status')
status
;;
*)
echo
echo "Usage: $0 { start | stop | restart | status }"
echo
exit 1
;;
esac
exit 0
1)
COMMAND="$CMD -p $PORT -l $LISTEN_IP -m $MEM_SIZE -v" — -v in Unix tradition very often is a shortcut for --verbose. All those dollar signs are variable expansion (their text values are inserted into the string assigned to new variable COMMAND).
2)
ps -ef | grep -v grep | grep $( cat $PID ) - it's a pipe: ps redirects its output to grep which outputs to another grep and the end result is printed to the standard output.
grep -v grep means "take all lines that do not contain 'grep'" (grep itself is a process, so you need to exclude it from output of ps). $( $command ) is a way to run command and insert its standard output into this place of script (in this case: cat $PID will show contents of file with name $PID).
3) kill_cmd.
This function is an endless loop trying to kill the LIST of 'memcached' processes' PIDs. First, it tries to send TERM signal (politely asking each process in $LIST to quit, saving its work and shutting down correctly), gives them 2 seconds (sleep 2) to do their shutdown job and then tries to make sure that all processes are killed using signal KILL (-9), which slays the process immediately using OS facilities: if a process has not done its shutdown work in 2 seconds, it's considered hung). If slaying with kill -9 was successful, it removes the PID file and quits the loop.
ps -ef | grep -v grep | grep $CMD | grep -w $USR | awk '{print $2}' prints all PIDs of processes with name $CMD ('memcached') and user $USR ('user'). -w option of grep means 'the Whole word only' (this excludes situations where the sought name is a part of another process name, like 'fakememcached'). awk is a little interpreter most often used to take a word number N from every line of input (you can consider it a selector for a column of a text table). In this case, it prints every second word in ps output lines, that means every PID.
If you have any other questions, I'll add answers below.
Here is an explanation of the pieces of code you do not understand:
1.
# Does this mean, that the COMMAND variable can adopt different values, depending on
# what is entered as parameter? "memcached" is chosen by default, port, ip address and
# memory size are options, but what is -v?
COMMAND="$CMD -p $PORT -l $LISTEN_IP -m $MEM_SIZE -v"
In the man, near -v:
$ man memcached
...
-v Be verbose during the event loop; print out errors and warnings.
...
2.
# ps -ef: Display uid, pid, parent pid, recent CPU usage, process start time,
# controling tty, elapsed CPU usage, and the associated command of all other processes
# that are owned by other users.
# The rest of this line I don't understand, especially grep -v grep
ps -ef | grep -v grep | grep $( cat $PID )
Print all processes details (ps -ef), exclude the line with grep (grep -v grep) (since you are running grep it will display itself in the process list) and filter by the text found in the file named $PID (/tmp/app.pid) (grep $( cat $PID )).
3.
# I don't understand this function :-(
kill_cmd() {
SIGNAL=""; MSG="Killing "
while true
do
## create a list with all the pid numbers filtered by command (memcached) and user ($USR)
LIST=`ps -ef | grep -v grep | grep $CMD | grep -w $USR | awk '{print $2}'`
## if $LIST is not empty... proceed
if [ "$LIST" ]
then
echo; echo "$MSG $LIST" ; echo
## kill all the processes in the $LIST (xargs will get the list from the pipe and put it at the end of the kill command; something like this < kill $SIGNAL $LIST > )
echo $LIST | xargs kill $SIGNAL
# Why this sleep command?
## some processes might take one or two seconds to perish
sleep 2
SIGNAL="-9" ; MSG="Killing $SIGNAL"
## if the file $PID still exists, delete it
if [ -f $PID ]
then
/bin/rm $PID
fi
## if list is empty
else
echo; echo "All killed..." ; echo
## get out of the while loop
break
fi
done
}
This function will kill all the processes related to memcached slowly and painfully (actually quite the opposite).
Above are the explanations.

Resources