views:

1019

answers:

6

We want to build a script that run every night (kills and restart a java process). For that we need to capture the process number (since there could be more than one java process running). The command below is basically what we will use to obtain the processes number, probably with a regexp at the end of the grep. Unless any better suggestions comes up.

root#ps -e |grep  'java'
18179 pts/0    00:00:43 java

We want to know how to parse the output above and get it into a shell variable so we can use the kill command as below.

kill -9 ${processid}
wait 10

Note1: The reason we cannot rely on the normal service stop command is because the processes sometimes does not want to die. And we have to use the kill command manually.

A: 

killing it:

ps -e | grep java | cut -f1 -d' ' | xargs kill -9

storing PID on variable:

export JAVAPID=`ps -e | grep 'java' | cut -f1 -d' '`

checking that it worked:

echo $JAVAPID
vartec
+4  A: 

There are a couple of options to solve this. If you're using bash, then the shell variable '$!' will contain the PID of the last forked-off child process. So, after you start your Java program, do something like:

echo $! > /var/run/my-process.pid

Then, after your init script stops the Java process:

# Get the pidfile.
pid=$(cat /var/run/my-process.pid)

# Wait ten seconds to stop our process.
for count in $(1 2 3 4 5 6 7 8 9 10); do
    sleep 1
    cat "/proc/$pid/cmdline" 2>/dev/null | grep -q java
    test $? -ne 0 && pid="" && break
done

# If we haven't stopped, kill the process.
if [ ! -z "$pid" ]; then
    echo "Not stopping; terminating with extreme prejudice."
    kill -9 $pid
fi

Make sure to remove the pidfile when you're done.

Don Werve
"Prejucide"? Is that a joke or a typo?
Michael Myers
That's what happens when I post an answer before the morning coffee.
Don Werve
Also, if you've got the 'seq' command, you can do 'seq 1 10' instead of the manual count. Isn't always available on every flavor of Linux, though.
Don Werve
+3  A: 
ps aux | grep java | awk '{print $1}' | xargs kill -9

Here's an explanation:

ps aux gives you a listing of all processes

grep java gives you all of the processes whose names and command line arguments contain the string "java"

awk '{print $1}' parses the output of the grep command into columns by whitespace and re-prints only the first column

xargs kill -9 passes each of the results of the awk command as parameters to a kill -9 command

Eli Courtwright
Skip the grep: ps aux | awk '/java/ { print $1 }' :)
andri
Thanks for the tip; I don't know awk well enough to have known how to do that. I'll leave my answer as it is because it's simpler for me personally to understand, but I'm glad you made that suggestion.
Eli Courtwright
Shouldn't you have a grep -v grep in there to stop it from collecting grep's pid (since its commandline contains the word java)?
Chas. Owens
Technically yes; I left that out for two reasons. First, when the kill command runs, that process id will be defunct, so it doesn't hurt to leave it in (though you will get a warning message). Second, it makes the call chain less complex for a newbie to understand. You have a good point though.
Eli Courtwright
+1  A: 

You can easily get the PID or list of PIDs into a variable using backticks and cut (or awk if preferred) to retrieve only the PID field:

[user@host ~]$ ps -e | grep java | cut -d' ' -f1
12812
12870
13008
13042
13060

Note in the above example I have multiple Java processes running hence the multiple values. If you save this into a variable like so:

JAVA_PROCS=`ps -e | grep java | cut -d' ' -f1`

You can iterate through the processes to kill them if desired:

for proc in $JAVA_PROCS; do
    kill -9 $proc; 
done

Of course, if you're only retrieving one process, then there's no need to iterate and you can just run it as:

kill -9 $JAVA_PROCS
Jay
+1  A: 

If you do what you suggest, you may end up capturing the grep itself and killing that (since your grep command contains the java string that you are searching for). You can work around this by excluding grep (by using another grep!):

pid=`ps -e | fgrep java | fgrep -v grep | awk '{print $1}'`
# check pid has a value
# kill $pid

You might also like ps -e -opid,args.

A better alternative is to use pgrep(1) or pkill(1) if your system has them. No more pipes, seds, awks, cuts, xargs:

pkill -9 java
Martin Carpenter
I almost posted the same thing, but ps -e doesn't list cmd arguments (at least on my box) so there's no danger of accidentally capturing the 'grep java' command itself in the grep output.
Jay
Spot on, Jay, at least for Linux. I still prefer pkill but it looks like I'm in a minority.
Martin Carpenter
You can also stick brackets around the first char in the grep, as ingrep [j]avaThe grep sees that as a regex and looks for a j, but the command line will not match the pattern. :) It makes me feel dirty when I do it, but it works well...
dannysauer
A: 

I use something like this:

kill $(ps -A | grep java | cut -b 1-5)
MarkusQ