Linux Script to selectively kill processes - linux

I'm looking at a way to automate the following:
Run ps -ef to list all processes.
Filter out those rows containing java in the CMD column.
Filter out those rows containing root in the UID column.
For each of the filtered rows, get the PID column and run pargs <PID>.
If the output of pargs <PID> contains a particular string XYZ, the issue a kill -9 <PID> command.
To filter out rows based on specific column values, is there a better way than grep? I can use
ps -ef | awk '{print $1}' | grep <UID>
but then I lose info from all other columns. The closest thing I have right now is:
ps -ef | grep java | grep root | grep -v grep | xargs pargs | ?????
EDIT
I was able to solve the problem by using a using the following script:
ps -ef | awk '/[j]ava/ && /root/ {print $2}' | while read PID; do
pargs "$PID" | grep "Args" > /dev/null && kill -9 $PID && echo "$PID : Java process killed!"
done
both anubhava's and kojiro's answers helped me reach there. But since I can only accept one answer, I tagged kojiro's answer as the correct one since it helped me a bit more.

Consider pgrep:
pgrep -U 0 java | while read pid; do
pargs "$pid" | grep -qF XYZ && kill "$pid"
done
pgrep and pkill are available on many Linux systems and as part of the "proctools" packages for *BSDs and OS X.

You can reduce all grep by using awk:
ps -ef | awk '/[j]ava/ && /root/ {print $1}' | xargs pargs
Searching for pattern /[j]ava/ will skip this awk process from output of ps.
You can also use pkill if it is available on your system.

Related

Multiple PIDs being stored in PID file

I have a System V init script I've developed that starts a Java program. For some reason whenever the PID file gets created, it contains multiple PIDs instead of one.
Here's the relevant code that starts the service and writes to the PID file:
daemon --pidfile=$pidfile "$JAVA_CMD &" >> $logfile 2>&1
RETVAL=$?
usleep 500000
if [ $RETVAL -eq 0 ]; then
touch "$lock"
PID=$(ps aux | grep -vE 'grep|runuser|bash' | grep <myservice> | awk '{print $2}')
echo $PID > $pidfile
When I test the ps aux... command manually, a single line returns. When running as a script, it appears that this call is returning multiple PIDs.
Example contents in the PID file: 16601 16602 16609 16619 16690. 16619 is the actual process ID found when manually running the ps aux... command mentioned above.
Try reversing your greps. The first one (-vE) may run BEFORE the myservice one starts up. Grep for your service FIRST, then filter out the unwanted lines:
PID=$(ps aux | grep <myservice> | grep -vE 'grep|runuser|bash' | awk '{print $2}')
I encounted the same issue but not the same statement, it was like this:
PID="$(ps -ef|grep command|grep options|grep -v grep|awk '{print $2}')"
in which I used the same grep order as #Marc said in first answer, but did not filter all the unwanted lines.
So I tried the below one and it worked:
PID="$(ps -ef|grep command|grep options|grep -vE 'grep|runuser|bash'|awk '{print $2}')"

Awk not working inside bash script

Im trying to write a bash script and trying to take input from user and executing a kill command to stop a specific tomcat.
...
read user_input
if [ "$user_input" = "2" ]
then
ps -ef | grep "search-tomcat" |awk {'"'"'print $2'"'"'}| xargs kill -9
echo "Search Tomcat Shut Down"
fi
...
I have confirmed that the line
ps -ef | grep "search-tomcat"
works fine in script but:
ps -ef | grep "search-tomcat" |awk {'"'"'print $2'"'"'}
doesnt yield any results in script, but gives desired output in terminal, so there has to be some problem with awk command
xargs can be tricky - Try:
kill -9 $(ps -ef | awk '/search-tomcat/ {print $2}')
If you prefer using xargs then check man page for options for your target OS (i.e. xargs -n.)
Also noting that 'kill -9' is a non-graceful process exit mechanism (i.e. possible file corruption, other strangeness) so I suggest only using as a last resort...
:)

Getting PID of process in Shell Script

I am writing one shell script and I want to get PID of one process with name as "ABCD". What i did was :
process_id=`/bin/ps -fu $USER|grep "ABCD"|awk '{print $2}'`
This gets PID of two processes i.e. of process ABCD and the GREP command itself what if I don't want to get PID of GREP executed and I want PID only of ABCD process?
Please suggest.
Just grep away grep itself!
process_id=`/bin/ps -fu $USER| grep "ABCD" | grep -v "grep" | awk '{print $2}'`
Have you tried to use pidof ABCD ?
It's very straight forward. ABCD should be replaced by your process name.
#!/bin/bash
processId=$(ps -ef | grep 'ABCD' | grep -v 'grep' | awk '{ printf $2 }')
echo $processId
Sometimes you need to replace ABCD by software name. Example - if you run a java program like java -jar TestJar.jar & then you need to replace ABCD by TestJar.jar.
ps has an option for that:
process_id=`/bin/ps -C ABCD -o pid=`
You can also do away with grep and use only awk.
Use awk's expression matching to match the process name but not itself.
/bin/ps -fu $USER | awk '/ABCD/ && !/awk/ {print $2}'
You can use this command to grep the pid of a particular process & echo $b to print pid of any running process:
b=`ps -ef | grep [A]BCD | awk '{ printf $2 }'`
echo $b
ps | pgrep ABCD
You can try the above command to return the process id of the ABCD process.
I found a better way to do this.
top -n 1 | grep "##" | grep -Eo '^[^ ]+'

Getting pids from ps -ef |grep keyword

I want to use ps -ef | grep "keyword" to determine the pid of a daemon process (there is a unique string in output of ps -ef in it).
I can kill the process with pkill keyword is there any command that returns the pid instead of killing it? (pidof or pgrep doesnt work)
You can use pgrep as long as you include the -f options. That makes pgrep match keywords in the whole command (including arguments) instead of just the process name.
pgrep -f keyword
From the man page:
-f The pattern is normally only matched against the process name. When -f is set, the full command line is used.
If you really want to avoid pgrep, try:
ps -ef | awk '/[k]eyword/{print $2}'
Note the [] around the first letter of the keyword. That's a useful trick to avoid matching the awk command itself.
Try
ps -ef | grep "KEYWORD" | awk '{print $2}'
That command should give you the PID of the processes with KEYWORD in them. In this instance, awk is returning what is in the 2nd column from the output.
ps -ef | grep KEYWORD | grep -v grep | awk '{print $2}'
This is available on linux: pidof keyword
I use
ps -C "keyword" -o pid=
This command should give you a PID number.
To kill a process by a specific keyword you could create an alias in ~/.bashrc (linux) or ~/.bash_profile (mac).
alias killps="kill -9 `ps -ef | grep '[k]eyword' | awk '{print $2}'`"

Kill random process with name

I want a way to kill a random process with a name (eg a random perl process).
What would be the best way of doing this?
I was thinkign of using something like this:
ps aux | grep PROCESS-NAME
to a file, then find a random line number, get the second column (process ID?) and kill that.
For my use it doesn't actually need to be a random one, as long as it kills one of the processes. Making it random just makes it better.
look at the -r option of the killall command!
Bash one-liner :-p
kill `ps auxww | grep zsh | awk '{print $2}' | while read line; do echo "$RANDOM $line"; done | sort | cut -d ' ' -f 2 | head -n 1`
There's also the 'pidof' command, which can be used to kill with:
kill `pidof processname`
To get just one process when there are multiple with the same name, use -s for "single shot".
It sounded like you were already on the right track.
you can use the following perl script, save it as randomline.pl, which will return a random line from whats piped into it
#!/usr/bin/perl
srand (time ^ $$ ^ unpack "%L*", `ps axww | gzip`);
while (<>) { push(#_,$_); } print #_[rand()*#_];
then run the following command to send the kill command
kill `ps aux | grep PROCESS-NAME | perl randomline.pl | awk '{print $2}'`
You might also want to add in some checking, perhaps with an inverted grep for root to make sure you don't try to kill root level processes that match your process name.
just kill and awk.
kill $(ps -eo cmd,pid|awk '/zsh/&&!/awk/{pid[$NF]}END{for(i in pid){print i;exit}}')
the for loop in the END block will give you you a random pid to kill
with recent bash shell
#!/bin/bash
declare -a pid
pid=( $(pidof myprocess) )
length=${#pid}
rnumber=$((RANDOM%length+1))
rand=$((rnumber-1))
kill ${pid[$rand]}
How about using pgrep and pkill. They allow lot of options to select the processes.
kill process with name "my_proc_name" :
kill -9 `ps xf | grep my_proc_name | grep -v grep | cut -d " " -f 1`
Maybe off topic, but I use this on Cygwin. Inspired by
Lev Victorovich Priyma’s answer
ps -W | awk '/calc.exe/,NF=1' | xargs kill -f
or
ps -W | awk '$0~z,NF=1' z=calc.exe | xargs kill -f

Resources