Start process if dead - linux

What I'm trying to do is to start a process if not started. Here is what I try
#!/bin/bash
pid=`ps ax | grep app | grep -v grep | wc -l`
if [ $pid = 0 ]
then
/etc/init.d/app start
fi
The problem is that the line
/etc/init.d/app start
is not executed. What is wrong here ?
I know that I can you daemontools but I like the "bash" approach.

Take a look at the == operator.
Best may be something like
pid=`ps ax | grep app | grep -v grep`
test -z "$pid" && /etc/init.d/app start

You can avoid the double grep by turning your keyword into a regex that doesn't match itself. And you can use grep -c instead of counting with wc. In your script, you could try:
pcount=`ps ax | grep -c "[a]pp"`
Alternately, use the actual pid instead of the process count:
#!/bin/bash
pid=`ps ax | awk '/[a]pp/{print $1}'`
if ! ps "$pid" >/dev/null; then
/etc/init.d/app start
fi
Note that this is still a very bad way to handle restarts of a service. You should see if app maintains its own pid file, perhaps somewhere in /var/run/, then test the contents of that.
#!/bin/sh
if [ -f /var/run/app.pid ]; then
if ps `cat /var/run/app.pid` >/dev/null; then
/etc/init.d/app start
fi
else
/etc/init.d/app start
fi
Or even better, launch app using daemontools runit or upstart or something equivalent that will take care of these things for you.

If you have GNU ps this is easy and doesn't require any craziness.
if ! ps -C app >/dev/null ; then
/etc/init.d/app start
fi
You just need to be careful that the app you pass to ps is the actual process name.

I can't check on my servers right now, but Debian use start-stop-daemon to load services, it seems the right tool to use for your task, since it keeps track of your background process by PID and not just matching a name in the process list (which can do too).

Related

Shutdown computer when all instances of a given program have finished

I use the following script to check whether wget has finished downloading. To check for this, I'm looking for its PID, and when it is not found the computer shutdowns. This works fine for a single instance of wget, however, I'd like the script to look for all already running wget programs.
#!/bin/bash
while kill -0 $(pidof wget) 2> /dev/null; do
for i in '-' '/' '|' '\'
do
echo -ne "\b$i"
sleep 0.1
done
done
poweroff
EDIT: I'd would be great if the script would check if at least one instance of wget is running and only then check whether wget has finished and shutdown the computer.
In addition to the other answers, you can satisfy your check for at least one wget pid by initially reading the result of pidof wget into an array, for example:
pids=($(pidof wget))
if ((${#pids[#]} > 0)); then
# do your loop
fi
This also brings up a way to routinely monitor the remaining pids as each wget operation completes, for example,
edit
npids=${#pids[#]} ## save original number of pids
while (( ${#pids[#]} -gt 0 )); do ## while pids remain
for ((i = 0; i < npids; i++)); do ## loop, checking remaining pids
kill -0 ${pids[i]} || pids[$i]= ## if not unset in array
done
## do your sleep and spin
done
poweroff
There are probably many more ways to do it. This is just one that came to mind.
I don't think kill is a right Idea,
may be some thing on the lines like this
while [ 1 ]
do
live_wgets=0
for pid in `ps -ef | grep wget| awk '{print $2}'` ; # Adjust the grep
do
live_wgets=$((live_wgets+1))
done
if test $live_wgets -eq 0; then # shutdown
sudo poweroff; # or whatever that suits
fi
sleep 5; # wait for sometime
done
You can adapt your script in the following way:
#!/bin/bash
spin[0]="-"
spin[1]="\\"
spin[2]="|"
spin[3]="/"
DOWNLOAD=`ps -ef | grep wget | grep -v grep`
while [ -n "$DOWNLOAD" ]; do
for i in "${spin[#]}"
do
DOWNLOAD=`ps -ef | grep wget | grep -v grep`
echo -ne "\b$i"
sleep 0.1
done
done
sudo poweroff
However I would recommend using cron instead of an active waiting approach or even use wait
How to wait in bash for several subprocesses to finish and return exit code !=0 when any subprocess ends with code !=0?

How to get watch to run a bash script with quotes

I'm trying to have a lightweight memory profiler for the matlab jobs that are run on my machine. There is either one or zero matlab job instance, but its process id changes frequently (since it is actually called by another script).
So here is the bash script that I put together to log memory usage:
#!/bin/bash
pid=`ps aux | grep '[M]ATLAB' | awk '{print $2}'`
if [[ -n $pid ]]
then
\grep VmSize /proc/$pid/status
else
echo "no pid"
fi
when I run this script in bash like this:
./script.sh
it works fine, giving me the following result:
VmSize: 1289004 kB
which is exactly what I want.
Now, I want to run this periodically. So I run it with watch, like this:
watch ./script.sh
But in this case I only receive:
no pid
Please note that I know the matlab job is still running, because I can see it with the same pid on top, and besides, I know each matlab job take several hours to finish.
I'm pretty sure that something is wrong with the quotes I have when setting pid. I just can't figure out how to fix it. Anyone knows what I'm doing wrong?
PS.
In the man page of watch, it says that commands are executed by sh -c. I did run my script like sh -c ./script and it works just fine, but watch doesn't.
Why don't you use a loop with sleep command instead?
For example:
#!/bin/bash
pid=`ps aux | grep '[M]ATLAB' | awk '{print $2}'`
while [ "1" ]
do
if [[ -n $pid ]]
then
\grep VmSize /proc/$pid/status
else
echo "no pid"
fi
sleep 10
done
Here the script sleeps(waits) for 10 seconds. You can set the interval you need changing the sleep command. For example to make the script sleep for an hour use sleep 1h.
To exit the script press Ctrl - C
This
pid=`ps aux | grep '[M]ATLAB' | awk '{print $2}'`
could be changed to:
pid=$(pidof MATLAB)
I have no idea why it's not working in watch but you could use a cron job and make the script log to a file like so:
#!/bin/bash
pid=$(pidof MATLAB) # Just to follow previously given advice :)
if [[ -n $pid ]]
then
echo "$(date): $(\grep VmSize /proc/$pid/status)" >> logfile
else
echo "$(date): no pid" >> logfile
fi
You'd of course have to create logfile with touch.
You might try just running ps command in watch. I have had issues in the past with watch chopping lines and such when they get too long.
It can be fixed by making the terminal you are running the command from wider or changing the column like this (may need to adjust the 160 to your liking):
export COLUMNS=160;

How to check if process is running in linux

I am trying to automatically check if a process is running or not and have to perform next steps accordingly. I had written a bash script but it doesn't seem to work.
if ps aux | grep [M]yProcessName > /dev/null
then
echo "Running"
else
echo "Not running"
fi
Is my if statement wrongly used?
You don't want to know if a particular process (of known pid) is running (this can be done by testing if /proc/1234/ exists for pid 1234) but if some process is running a given command (or a given executable).
Notice that the kill(2) syscall can be portably used to check if a given process is running (with a 0 signal, e.g. kill(pid,0)). From inside a program, this is a common way to check that a process of known pid is still existing and running (or waiting).
You could use the pidof command to find the processes running some executable, e.g. pidof zsh to find all the zsh processes. You could also use killall -s 0 zsh
And you might be interested by the pgrep utility and the /proc filesystem.
ps aux | grep [M]yProcessName | grep -v grep
Using -z to check if a string is empty or not, something like this could work:
line=$(ps aux | grep [M]yProcessName)
if [ -z "$line" ]
then
echo "Not Running"
else
echo $line > /dev/null
echo "Rinnung"
fi
There is a solution:
if [ "$(ps aux | grep "what you need" | awk '{print $11}')" == "grep" ]; then ... elif [ ... ]; then ... else ... fi
This works fine in Debian 6. '{print $11}' is needed, because the sytem treats grep as a process as well
processid =$(ps aux | grep 'ProcessName' | grep -v grep| awk '{print $2}')
The above command will give you the process id. Assign that process id to a variable and do this -->
if cat /proc/$processid/status | grep "State: R (running)" > /dev/null
then
echo "Running"
else
echo "Not running"
fi
SMBD=$(pidof smbd)
if [ "$SMBD" == "" ];
then
/etc/init.d/samba start;
else
/etc/init.d/samba restart;
fi
On my system, ps aux | grep ProcessName always get a line of that grep process like:
edw4rd 9653 0.0 0.0 4388 832 pts/1 S+ 21:09 0:00 grep --color=auto ProcessName
So, the exit status is always 0. Maybe that's why your script doesn't work.
return 0 means success while others failed
kill -0 `pid`; echo $?
Just to explicitly mention a way this answer alluded to, pgrep is the best way to do this by process name:
pgrep [M]yProcessName
If a process whose name matches "[M]yProcessName" is running, pgrep will print its PID to stdout and will exit with code 0. Otherwise, it will print nothing and exit with code 1.
try this
ps aux | grep [M]yProcessName | grep -v grep

Linux/Unix command to determine if process is running?

I need a platform independent (Linux/Unix|OSX) shell/bash command that will determine if a specific process is running. e.g. mysqld, httpd...
What is the simplest way/command to do this?
While pidof and pgrep are great tools for determining what's running, they are both, unfortunately, unavailable on some operating systems. A definite fail safe would be to use the following: ps cax | grep command
The output on Gentoo Linux:
14484 ? S 0:00 apache2
14667 ? S 0:00 apache2
19620 ? Sl 0:00 apache2
21132 ? Ss 0:04 apache2
The output on OS X:
42582 ?? Z 0:00.00 (smbclient)
46529 ?? Z 0:00.00 (smbclient)
46539 ?? Z 0:00.00 (smbclient)
46547 ?? Z 0:00.00 (smbclient)
46586 ?? Z 0:00.00 (smbclient)
46594 ?? Z 0:00.00 (smbclient)
On both Linux and OS X, grep returns an exit code so it's easy to check if the process was found or not:
#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
Furthermore, if you would like the list of PIDs, you could easily grep for those as well:
ps cax | grep httpd | grep -o '^[ ]*[0-9]*'
Whose output is the same on Linux and OS X:
3519 3521 3523 3524
The output of the following is an empty string, making this approach safe for processes that are not running: echo ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'
This approach is suitable for writing a simple empty string test, then even iterating through the discovered PIDs.
#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
echo "Process not running." 1>&2
exit 1
else
for PID in $PIDS; do
echo $PID
done
fi
You can test it by saving it to a file (named "running") with execute permissions (chmod +x running) and executing it with a parameter: ./running "httpd"
#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
WARNING!!!
Please keep in mind that you're simply parsing the output of ps ax which means that, as seen in the Linux output, it is not simply matching on processes, but also the arguments passed to that program. I highly recommend being as specific as possible when using this method (e.g. ./running "mysql" will also match 'mysqld' processes). I highly recommend using which to check against a full path where possible.
References:
http://linux.about.com/od/commands/l/blcmdl1_ps.htm
http://linux.about.com/od/commands/l/blcmdl1_grep.htm
You SHOULD know the PID !
Finding a process by trying to do some kind of pattern recognition on the process arguments (like pgrep "mysqld") is a strategy that is doomed to fail sooner or later. What if you have two mysqld running? Forget that approach. You MAY get it right temporarily and it MAY work for a year or two but then something happens that you haven't thought about.
Only the process id (pid) is truly unique.
Always store the pid when you launch something in the background. In Bash this can be done with the $! Bash variable. You will save yourself SO much trouble by doing so.
How to determine if process is running (by pid)
So now the question becomes how to know if a pid is running.
Simply do:
ps -o pid= -p <pid>
This is POSIX and hence portable. It will return the pid itself if the process is running or return nothing if the process is not running. Strictly speaking the command will return a single column, the pid, but since we've given that an empty title header (the stuff immediately preceding the equals sign) and this is the only column requested then the ps command will not use header at all. Which is what we want because it makes parsing easier.
This will work on Linux, BSD, Solaris, etc.
Another strategy would be to test on the exit value from the above ps command. It should be zero if the process is running and non-zero if it isn't. The POSIX spec says that ps must exit >0 if an error has occurred but it is unclear to me what constitutes 'an error'. Therefore I'm not personally using that strategy although I'm pretty sure it will work as well on all Unix/Linux platforms.
On most Linux distributions, you can use pidof(8).
It will print the process ids of all running instances of specified processes, or nothing if there are no instances running.
For instance, on my system (I have four instances of bashand one instance of remmina running):
$ pidof bash remmina
6148 6147 6144 5603 21598
On other Unices, pgrep or a combination of ps and grep will achieve the same thing, as others have rightfully pointed out.
This should work on most flavours of Unix, BSD and Linux:
PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep
Tested on:
SunOS 5.10 [Hence the PATH=...]
Linux 2.6.32 (CentOS)
Linux 3.0.0 (Ubuntu)
Darwin 11.2.0
FreeBSD 9.0-STABLE
Red Hat Enterprise Linux ES release 4
Red Hat Enterprise Linux Server release 5
The simpliest way is to use ps and grep:
command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
echo "Command is running"
else
echo "Command is not running"
fi
If your command has some command arguments, then you can also put more 'grep cmd_arg1' after 'grep $command' to filter out other possible processes that you are not interested in.
Example: show me if any java process with supplied argument:
-Djava.util.logging.config.file=logging.properties
is running
ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l
Putting the various suggestions together, the cleanest version I was able to come up with (without unreliable grep which triggers parts of words) is:
kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
kill -0 doesn't kill the process but checks if it exists and then returns true, if you don't have pidof on your system, store the pid when you launch the process:
$ mysql &
$ echo $! > pid_stored
then in the script:
kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
Just a minor addition: if you add the -c flag to ps, you don't need to remove the line containing the grep process with grep -v afterwards. I.e.
ps acux | grep cron
is all the typing you'll need on a bsd-ish system (this includes MacOSX) You can leave the -u away if you need less information.
On a system where the genetics of the native ps command point back to SysV, you'd use
ps -e |grep cron
or
ps -el |grep cron
for a listing containing more than just pid and process name. Of course you could select the specific fields to print out using the -o <field,field,...> option.
I use pgrep -l httpd but not sure it is present on any platform...
Who can confirm on OSX?
This approach can be used in case commands 'ps', 'pidof' and rest are not available.
I personally use procfs very frequently in my tools/scripts/programs.
egrep -m1 "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3
Little explanation what is going on:
-m1 - stop process on first match
"mysqld$|httpd$" - grep will match lines which ended on mysqld OR httpd
/proc/[0-9]* - bash will match line which started with any number
cut - just split the output by delimiter '/' and extract field 3
You should know the PID of your process.
When you launch it, its PID will be recorded in the $! variable. Save this PID into a file.
Then you will need to check if this PID corresponds to a running process. Here's a complete skeleton script:
FILE="/tmp/myapp.pid"
if [ -f $FILE ];
then
PID=$(cat $FILE)
else
PID=1
fi
ps -o pid= -p $PID
if [ $? -eq 0 ]; then
echo "Process already running."
else
echo "Starting process."
run_my_app &
echo $! > $FILE
fi
Based on the answer of peterh. The trick for knowing if a given PID is running is in the ps -o pid= -p $PID instruction.
None of the answers worked for me, so heres mine:
process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
echo "Process is not running."
else
echo "Process is running."
fi
Explanation:
|tr -d '\n'
This removes the carriage return created by the terminal. The rest can be explained by this post.
This prints the number of processes whose basename is "chromium-browser":
ps -e -o args= | awk 'BEGIN{c=0}{
if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"
If this prints "0", the process is not running. The command assumes process path does not contain breaking space. I have not tested this with suspended processes or zombie processes.
Tested using gwak as the awk alternative in Linux.
Here is a more versatile solution with some example usage:
#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
local quiet=1;
shift
else
local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
name=$2
if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}
process='chromium-browser'
printf "Process \"${process}\" is "
if isProcessRunning -q "$process"
then printf "running.\n"
else printf "not running.\n"; fi
printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"
Here is my version. Features:
checks for exact program name (first argument of the function). search for "mysql" will not match running "mysqld"
searches program arguments (second argument of the function)
script:
#!/bin/bash
# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
for i in $(pidof $1); do
cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
if [ $? -eq 0 ]; then
return 0
fi
done
return 1
}
isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
echo "not running, starting..."
fi
[ $pid ] && [ -d /proc/$pid ] && command if you know the pid
The following shell function, being only based on POSIX standard commands and options should work on most (if not any) Unix and linux system. :
isPidRunning() {
cmd=`
PATH=\`getconf PATH\` export PATH
ps -e -o pid= -o comm= |
awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
`
[ -n "$cmd" ] &&
printf "%s is running\n%s\n\n" "$1" "$cmd" ||
printf "%s is not running\n\n" $1
[ -n "$cmd" ]
}
$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd
$ isPidRunning ksh
ksh is running
5230 ksh
$ isPidRunning bash
bash is not running
Note that it will choke when passed the dubious "0]" command name and will also fail to identify processes having an embedded space in their names.
Note too that the most upvoted and accepted solution demands non portable ps options and gratuitously uses a shell that is, despite its popularity, not guaranteed to be present on every Unix/Linux machine (bash)

How can I kill a process by name instead of PID, on Linux? [duplicate]

This question already has answers here:
Find and kill a process in one line using bash and regex
(30 answers)
Closed 1 year ago.
Sometimes when I try to start Firefox it says "a Firefox process is already running". So I have to do this:
jeremy#jeremy-desktop:~$ ps aux | grep firefox
jeremy 7451 25.0 27.4 170536 65680 ? Sl 22:39 1:18 /usr/lib/firefox-3.0.1/firefox
jeremy 7578 0.0 0.3 3004 768 pts/0 S+ 22:44 0:00 grep firefox
jeremy#jeremy-desktop:~$ kill 7451
What I'd like is a command that would do all that for me. It would take an input string and grep for it (or whatever) in the list of processes, and would kill all the processes in the output:
jeremy#jeremy-desktop:~$ killbyname firefox
I tried doing it in PHP but exec('ps aux') seems to only show processes that have been executed with exec() in the PHP script itself (so the only process it shows is itself.)
pkill firefox
More information: http://linux.about.com/library/cmd/blcmdl1_pkill.htm
Also possible to use:
pkill -f "Process name"
For me, it worked up perfectly. It was what I have been looking for.
pkill doesn't work with name without the flag.
When -f is set, the full command line is used for pattern matching.
You can kill processes by name with killall <name>
killall sends a signal to all
processes running any of the specified
commands. If no signal name is
specified, SIGTERM is sent.
Signals can be specified either by
name (e.g. -HUP or -SIGHUP ) or by number (e.g.
-1) or by option -s.
If the command name is not regular
expression (option -r) and contains a
slash (/), processes executing that
particular file will be selected for
killing, independent of their name.
But if you don't see the process with ps aux, you probably won't have the right to kill it ...
A bit longer alternative:
kill `pidof firefox`
The easiest way to do is first check you are getting right process IDs with:
pgrep -f [part_of_a_command]
If the result is as expected. Go with:
pkill -f [part_of_a_command]
If processes get stuck and are unable to accomplish the request you can use kill.
kill -9 $(pgrep -f [part_of_a_command])
If you want to be on the safe side and only terminate processes that you initially started add -u along with your username
pkill -f [part_of_a_command] -u [username]
Kill all processes having snippet in startup path. You can kill all apps started from some directory by for putting /directory/ as a snippet. This is quite usefull when you start several components for the same application from the same app directory.
ps ax | grep <snippet> | grep -v grep | awk '{print $1}' | xargs kill
* I would prefer pgrep if available
Strange, but I haven't seen the solution like this:
kill -9 `pidof firefox`
it can also kill multiple processes (multiple pids) like:
kill -9 `pgrep firefox`
I prefer pidof since it has single line output:
> pgrep firefox
6316
6565
> pidof firefox
6565 6316
Using killall command:
killall processname
Use -9 or -KILL to forcefully kill the program (the options are similar to the kill command).
On Mac I could not find the pgrep and pkill neither was killall working so wrote a simple one liner script:-
export pid=`ps | grep process_name | awk 'NR==1{print $1}' | cut -d' ' -f1`;kill $pid
If there's an easier way of doing this then please share.
To kill with grep:
kill -9 `pgrep myprocess`
more correct would be:
export pid=`ps aux | grep process_name | awk 'NR==1{print $2}' | cut -d' ' -f1`;kill -9 $pid
I normally use the killall command.
Check this link for details of this command.
I was asking myself the same question but the problem with the current answers is that they don't safe check the processes to be killed so... it could lead to terrible mistakes :)... especially if several processes matches the pattern.
As a disclaimer, I'm not a sh pro and there is certainly room for improvement.
So I wrote a little sh script :
#!/bin/sh
killables=$(ps aux | grep $1 | grep -v mykill | grep -v grep)
if [ ! "${killables}" = "" ]
then
echo "You are going to kill some process:"
echo "${killables}"
else
echo "No process with the pattern $1 found."
return
fi
echo -n "Is it ok?(Y/N)"
read input
if [ "$input" = "Y" ]
then
for pid in $(echo "${killables}" | awk '{print $2}')
do
echo killing $pid "..."
kill $pid
echo $pid killed
done
fi
kill -9 $(ps aux | grep -e myprocessname| awk '{ print $2 }')
If you run GNOME, you can use the system monitor (System->Administration->System Monitor) to kill processes as you would under Windows. KDE will have something similar.
The default kill command accepts command names as an alternative to PID. See kill (1). An often occurring trouble is that bash provides its own kill which accepts job numbers, like kill %1, but not command names. This hinders the default command. If the former functionality is more useful to you than the latter, you can disable the bash version by calling
enable -n kill
For more info see kill and enable entries in bash (1).
ps aux | grep processname | cut -d' ' -f7 | xargs kill -9 $
awk oneliner, which parses the header of ps output, so you don't need to care about column numbers (but column names). Support regex. For example, to kill all processes, which executable name (without path) contains word "firefox" try
ps -fe | awk 'NR==1{for (i=1; i<=NF; i++) {if ($i=="COMMAND") Ncmd=i; else if ($i=="PID") Npid=i} if (!Ncmd || !Npid) {print "wrong or no header" > "/dev/stderr"; exit} }$Ncmd~"/"name"$"{print "killing "$Ncmd" with PID " $Npid; system("kill "$Npid)}' name=.*firefox.*

Resources