I have this init.d script where i am checking the status of an application, The expected output should be
"Application is running with PID: XXXX"
Anyways, i'll show you the code that i have used:
ps -ef|grep -v grep |grep Jazz |grep -v "Jazz status"|awk '{ if ( $2 != "") print "Jazz Running with PID:",$2"; else print "Jazz not running";}'
When i run this on the terminal i get the following output:
Jazz Running with PID: 6261
Jazz Running with PID: 30077
When i remove the print statement and output $2 i get the following output:
#ps -ef|grep -v grep |grep Jazz |grep -v "Jazz status"|awk '{ if ( $2 != "") print $2}'
300077
I expect the output to be
Jazz Running with PID: 300773
I am stumped as to why i am getting two PID's in the first case?
P.S the first PID keeps changing, similar to showing me the PID of the command itself.
Edit:
Output of: ps -ef|grep Jazz
netcool 12744 1 5 13:03 ? 00:06:06 /opt/IBM/tivoli/webSphere/AppServer/java/bin/java -Declipse.security -Dwas.status.socket=38692 -Dosgi.install.area=/opt/IBM/tivoli/webSphere/AppServer -Dosgi.configuration.area=/opt/IBM/tivoli/jazzSM/profile/servers/server1/configuration -Djava.awt.headless=true -Dosgi.framework.extensions=com.ibm.cds,com.ibm.ws.eclipse.adaptors -Xshareclasses:name=webspherev85_1.6_64_%g,nonFatal -Xbootclasspath/p:/opt/IBM/tivoli/webSphere/AppServer/java/jre/lib/ibmorb.jar -classpath /opt/IBM/tivoli/jazzSM/profile/properties:/opt/IBM/tivoli/webSphere/AppServer/properties:/opt/IBM/tivoli/webSphere/AppServer/lib/startup.jar:/opt/IBM/tivoli/webSphere/AppServer/lib/bootstrap.jar:/opt/IBM/tivoli/webSphere/AppServer/lib/jsf-nls.jar:/opt/IBM/tivoli/webSphere/AppServer/lib/lmproxy.jar:/opt/IBM/tivoli/webSphere/AppServer/lib/urlprotocols.jar:/opt/IBM/tivoli/webSphere/AppServer/deploytool/itp/batchboot.jar:/opt/IBM/tivoli/webSphere/AppServer/deploytool/itp/batch2.jar:/opt/IBM/tivoli/webSphere/AppServer/java/lib/tools.jar -Dibm.websphere.internalClassAccessMode=allow -Xms512m -Xmx1024m -Xcompressedrefs -Xscmaxaot4M -Xscmx60M -Dws.ext.dirs=/opt/IBM/tivoli/webSphere/AppServer/java/lib:/opt/IBM/tivoli/jazzSM/profile/classes:/opt/IBM/tivoli/webSphere/AppServer/classes:/opt/IBM/tivoli/webSphere/AppServer/lib:/opt/IBM/tivoli/webSphere/AppServer/installedChannels:/opt/IBM/tivoli/webSphere/AppServer/lib/ext:/opt/IBM/tivoli/webSphere/AppServer/web/help:/opt/IBM/tivoli/webSphere/AppServer/deploytool/itp/plugins/com.ibm.etools.ejbdeploy/runtime -Dderby.system.home=/opt/IBM/tivoli/webSphere/AppServer/derby -Dcom.ibm.itp.location=/opt/IBM/tivoli/webSphere/AppServer/bin -Djava.util.logging.configureByServer=true -Duser.install.root=/opt/IBM/tivoli/jazzSM/profile -Djava.ext.dirs=/opt/IBM/tivoli/webSphere/AppServer/tivoli/tam:/opt/IBM/tivoli/webSphere/AppServer/java/jre/lib/ext -Djavax.management.builder.initial=com.ibm.ws.management.PlatformMBeanServerBuilder -Dpython.cachedir=/opt/IBM/tivoli/jazzSM/profile/temp/cachedir -Dwas.install.root=/opt/IBM/tivoli/webSphere/AppServer -Djava.util.logging.manager=com.ibm.ws.bootstrap.WsLogManager -Dserver.root=/opt/IBM/tivoli/jazzSM/profile -Dcom.ibm.security.jgss.debug=off -Dcom.ibm.security.krb5.Krb5Debug=off -Dfas.install.location=/opt/IBM/tivoli/jazzSM/admin -Dfas.ui.install.location=/opt/IBM/tivoli/jazzSM/admin_ui -Djava.library.path=/opt/IBM/tivoli/webSphere/AppServer/lib/native/linux/x86_64/:/opt/IBM/tivoli/webSphere/AppServer/java/jre/lib/amd64/default:/opt/IBM/tivoli/webSphere/AppServer/java/jre/lib/amd64:/opt/IBM/tivoli/webSphere/AppServer/bin:/usr/lib:/opt/IBM/tivoli/jazzSM/reporting/cognos/bin64: -Djava.endorsed.dirs=/opt/IBM/tivoli/webSphere/AppServer/endorsed_apis:/opt/IBM/tivoli/webSphere/AppServer/java/jre/lib/endorsed:/opt/IBM/tivoli/webSphere/AppServer/endorsed_apis:/opt/IBM/tivoli/webSphere/AppServer/java/jre/lib/endorsed -Djava.security.auth.login.config=/opt/IBM/tivoli/jazzSM/profile/properties/wsjaas.conf -Djava.security.policy=/opt/IBM/tivoli/jazzSM/profile/properties/server.policy com.ibm.wsspi.bootstrap.WSPreLauncher -nosplash -application com.ibm.ws.bootstrap.WSLauncher com.ibm.ws.runtime.WsServer /opt/IBM/tivoli/jazzSM/profile/config JazzSMNode01Cell JazzSMNode01 server1
netcool 19735 19678 0 14:50 pts/0 00:00:00 grep Jazz
Edit
Full init.d script that i have used:
#!/bin/sh
USER="xxxxxxx"
PASSWORD="xxxxxx"
start() {
su - netcool -c "/opt/IBM/tivoli/jazzSM/profile/bin/startServer.sh server1"
RETVAL=$?
return $RETVAL
}
stop() {
su - netcool -c "/opt/IBM/tivoli/jazzSM/profile/bin/stopServer.sh server1 -username ${USER} -password ${PASSWORD}"
RETVAL=$?
return $RETVAL
}
status() {
ps -ef|grep -v grep |grep Jazz |grep -v awk |grep -v "Jazz status" |awk '{ if ( $2!= "") print "Jazz is running with PID:",$2; else print "Jazz is not running";}'
#pid=$(pgrep -f Jazz) && echo "Jazz Running with PID: $pid" || echo "Jazz is not running"
}
case $1 in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart"|"reload")
stop
start
;;
*)
echo "usage: $0 {start|stop|status|restart|reload}"
RETVAL=1
esac
exit 0
Hope this helps
UPDATE
Based upon #jlliagre suggestion, running the following command still gave me more than one PID as the output:
[root#hjkpnlinst04 ~]# pid=$(pgrep -f jazzSM) && echo "Jazz Running with PID: $pid" || echo "Jazz is not running"
Jazz Running with PID: 12744
13176
13299
For now i am running this command, which seems to give me the required output when the process is running, however fails to give me the "else" output when the process is not running:
ps -ef|grep -v grep |grep Jazz |grep -v awk |grep -v "Jazz status" |awk '{ if ( $2!= "") print "Jazz is running with PID:",$2; else print "Jazz is not running";}'
That command should work (assuming pgrep is available):
pid=$(pgrep -f JazzSMNode01Cell) && echo "Jazz Running with PID: $pid" || echo "Jazz is not running"
Most likely you are finding awk. You are excluding grep, but not awk.
Better way to do this is using the pgrep command, e.g.:
echo "java is running with pids ", `pgrep java`
will list all pids Java processes are running with. It looks at the process image name only, not on the command line. I am not sure how portable pgrep is but it is there on Linux, FreeBSD and OS X, so good enough for me.
But looking at your updated answer I see that you are looking for the command line keyword, so like #jlliagre suggests, you should use -f switch. The advantage of pgrep is that it is smart enough to exclude itself, unlike the chain of awks and greps.
Related
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 ?
I need a shell script to kill a particular running process after a specific time by getting the process name and time as input.
I'm using centos machine i've tried the script but couldn't complete on killing the process on particular timing.
#!/bin/bash
read -p 'Process: ' name
read -p 'Timecontrol: ' time
ps -ef | grep $name | awk '{print $5}'
pkill -9 "$name"
the expected output to be kill the process in specific time which will be given as input.
With this script you can kill the running process at a specific time by giving the process name and the time.
[Note: The input for time must be in seconds only, i.e 120 for 2 minutes]
#!/bin/bash
LOG=/tmp/kill.log
EXIT_ON_KILL=true
read -p 'Process: ' name
read -p 'killat: ' time
PID=$(ps -ef | grep $name | awk '{print $2}')
ps -ef | grep $name | awk '{print $2}' &>>$LOG
if [ $? -eq 0 ]; then
echo -e "\n The process details "
ps -p $PID
else
echo -e "\nInvalid Process Name"
fi
current=$(date +"%T")
killat=$(date -d "+"$time" seconds" "+%T")
echo -e "\nCurrent time $current \nThe time target is $killat"
while :
do
current=$(date +"%T")
echo $current
if [ "${killat}" == "${current}" ]
then
kill -9 $PID &>>$LOG
if [ $? -eq 0 ]; then
echo "Process $name have been successfully killed"
if [ $EXIT_ON_KILL == true ];then
exit 0
fi
else
echo -e "\nFailed to Kill process $name"
echo -e "\nMay be Invalid Process Name"
exit 1
fi
fi
sleep 2
done
Sample Input:
Process: xxxx
Killat: 120
You can use a cron job to terminate the process in specific date and time.
If you have to use a script:
#!/bin/bash
read -p 'Process: ' name
read -p 'Timecontrol: ' timecontrol
while :
do
now="$(date --date="$(date +%H:%M)" +%s)"
x="$(date --date="$timecontrol" +%s)"
if [ $now == $x ]
then
ps -ef | grep $name | awk '{print $5}'
fi
done
Note:
Remove # if you plan to run this script forever.
The script will not kill the process at that particular time which you want to give it as an input as the script will run and die it will not wait for a specific time.
You can tickle this in two ways.
Loop but again it will run in the foreground
Cronjob
#!/bin/bash
EXIT_ON_KILL=true
read -p 'Process: ' name
read -p 'Timecontrol: ' timecontrol
while :
do
current_time=$(date +"%T")
echo $current_time "control "
current_time=$(echo $current_time | cut -d':' -f1-2)
if [ "${timecontrol}" == "${current_time}" ]
then
echo "killing process"
kill -9 $(ps -ef | grep $name | awk '{print $2}')
if [ $? -eq 0 ]; then
echo "Process killed having name $name and having $pid"
if [ $EXIT_ON_KILL == true ];then
exit 0
fi
else
echo "Failed to Kill process having name $name"
exit 1
fi
fi
sleep 2
done
awk '{print $2}' this return PID in ubuntu, you have to check-in Centos if it returns PID if not then change it to awk '{print $5}'
So you can run with
./kill_process.sh
Process: node
Timecontrol: 00:21
With Cron job, you do not need to pass time, just pass the name of the process and the script will run on the specified time and will kill the process.
#!/bin/bash
EXIT_ON_KILL=true
p_name=$1
kill -9 $(ps -ef | grep $p_name | awk '{print $2}')
if [ $? -eq 0 ]; then
echo "Process killed having name $p_name and having $pid"
if [ $EXIT_ON_KILL == true ];then
exit 0
fi
else
echo "Failed to Kill process having name $p_name"
exit 1
fi
Create-cron-job-on-CentOS
0 0 * * * /path_to_script/kill_process.sh node
This will kill process every-day-at-midnight
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
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
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.