KSH - Linux - ps -ef - Return code versus number of processes found - linux

Regarding the *nix ps -ef command. We have a number of shell scripts on an older AIX that use the ps -ef command to search out and see if a specific process "name" is currently running or not. The typical usage I see it :
ps -ef | grep java | grep RUDaemon | grep -v grep
rc=$?
if (( rc > 0 ))
then
...do process-exists stuff...
else
...do process-does-not-exists stuff...
fi
Thing is, the code doesn't appear to be working on our newer Linux...i.e., the rc now appears to be returning a simple 'status' outcome of the command itself, not the number of processes it found...Since I didn't write the original scripts, I'm not sure the original code EVER worked correctly. But the requirements state we need to utilize native *nix commands, so I re-wrote the code in the following manner and TESTED it for both 'exist' and 'does-not-exist' conditions.
rc=$(ps -ef | grep java | grep RUDaemon | grep -v grep | wc -l)
if (( rc > 0 ))
then
...do process-exists stuff...
else
...do process-does-not-exists stuff...
fi
My question is, what is the proper usage of ps -ef to discover the number of processes running with a specific name or partial name?
tia, Adym

Since you want not only discover … processes running with a specific name, but also with a specific argument, the principle usage is what you showed. But it can be optimized:
ps -ef | grep java | grep RUDaemon | grep -v grep
can be replaced with
ps -fCjava | grep RUDaemon
if indeed java processes with RUDaemon among the arguments are wanted.

Related

Bash: if statement always succeeding

I have the following if statement to check if a service, newrelic-daemon in this case, is running...
if [ $(ps -ef | grep -v grep | grep newrelic-daemon | wc -l) > 0 ]; then
echo "New Relic is already running."
The problem is it's always returning as true, i.e. "New Relic is already running". Even though when I run the if condition separately...
ps -ef | grep -v grep | grep newrelic-daemon | wc -l
... it returns 0. I expect it to do nothing here as the value returned is =0 but my IF condition says >0.
Am I overlooking something here?
You are trying to do a numeric comparison in [...] with >. That doesn't work; to compare values as numbers, use -gt instead:
if [ "$(ps -ef | grep -v grep | grep -c newrelic-daemon)" -gt 0 ]; then
The quotation marks around the command expansion prevent a syntax error if something goes horribly wrong (e.g. $PATH set wrong and the shell can't find grep). Since you tagged this bash specifically, you could also just use [[...]] instead of [...] and do without the quotes.
As another Bash-specific option, you could use ((...)) instead of either form of square brackets. This version is more likely to generate a syntax error if anything goes wrong (as the arithmetic expression syntax really wants all arguments to be numbers), but it lets you use the more natural comparison operators:
if (( "$(ps -ef | grep -v grep | grep -c newrelic-daemon)" > 0 )); then
In both cases I used grep -c instead of grep | wc -l; that way I avoided an extra process and a bunch of interprocess I/O just so wc can count lines that grep is already enumerating.
But since you're just checking to see if there are any matches at all, you don't need to do either of those; the last grep will exit with a true status if it finds anything and false if it doesn't, so you can just do this:
if ps -ef | grep -v grep | grep -q newrelic-daemon; then
(The -q keeps grep from actually printing out the matching lines.)
Also, if the process name you're looking for is a literal string instead of a variable, my favorite trick for this task is to modify that string like this, instead of piping through an extra grep -v grep:
if ps -ef | grep -q 'newrelic[-]daemon'; then
You can pick any character to put the square brackets around; the point is to create a regular expression pattern that matches the target process name but doesn't match the pattern itself, so the grep process doesn't find its own ps line.
Finally, since you tagged this linux, note that most Linux distros ship with a combination ps + grep command called pgrep, which does this for you without your having to build a pipeline:
if pgrep newrelic-daemon >/dev/null; then
(The MacOS/BSD version of pgrep accepts a -q option like grep, which would let you do without the >/dev/null redirect, but the versions I've found on Linux systems don't seem to have that option.)
There's also pidof; I haven't yet encountered a system that had pidof without pgrep, but should you come across one, you can use it the same way:
if pidof newrelic-daemon >/dev/null; then
Other answers have given you more details. I would do what you are trying to do with:
if pidof newrelic-daemon >/dev/null; then
echo "New Relic is already running."
fi
or even
pidof newrelic-daemon >/dev/null && echo "New Relic is already running."
If you want to compare integers with test you have to use the -gt option. See:
man test
or
man [
#Stephen: Try(change [ to [[ into your code along with fi which will complete the if block completely):
if [[ $(ps -ef | grep -v grep | grep newrelic-daemon | wc -l) > 0 ]]; then
echo "New Relic is already running."
fi

how can I kill a process in a shell script

My bash script has:
ps aux | grep foo.jar | grep -v grep | awk '{print $2}' | xargs kill
However, I get the following when running:
usage: kill [ -s signal | -p ] [ -a ] pid ...
kill -l [ signal ]
Any ideas, how to fix this line?
In general, your command is correct. If a foo.jar process is running, its PID will be passed to kill and (should) terminate.
Since you're getting kill's usage as output, it means you're actually calling kill with no arguments (try just running kill on its own, you'll see the same message). That means that there's no output in the pipeline actually reaching xargs, which in turn means foo.jar is not running.
Try running ps aux | grep foo.jar | grep -v grep and see if you're actually seeing results.
As much as you may enjoy a half dozen pipes in your commands, you may want to look at the pkill command!
DESCRIPTION
The pkill command searches the process table on the running system and signals all processes that match the criteria
given on the command line.
i.e.
pkill foo.jar
Untested and a guess at best (be careful)
kill -9 $(ps -aux | grep foo.jar | grep -v grep | awk '{print $2}')
I re-iterate UNTESTED as I'm not at work and have no access to putty or Unix.
My theory is to send the kill -9 command and get the process id from a sub shell command call.

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...
:)

Linux Script to selectively kill processes

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.

Finding process count in Linux via command line

I was looking for the best way to find the number of running processes with the same name via the command line in Linux. For example if I wanted to find the number of bash processes running and get "5". Currently I have a script that does a 'pidof ' and then does a count on the tokenized string. This works fine but I was wondering if there was a better way that can be done entirely via the command line. Thanks in advance for your help.
On systems that have pgrep available, the -c option returns a count of the number of processes that match the given name
pgrep -c command_name
Note that this is a grep-style match, not an exact match, so e.g. pgrep sh will also match bash processes. If you want an exact match, also use the -x option.
If pgrep is not available, you can use ps and wc.
ps -C command_name --no-headers | wc -l
The -C option to ps takes command_name as an argument, and the program prints a table of information about processes whose executable name matches the given command name. This is an exact match, not grep-style. The --no-headers option suppresses the headers of the table, which are normally printed as the first line. With --no-headers, you get one line per process matched. Then wc -l counts and prints the number of lines in its input.
result=`ps -Al | grep command-name | wc -l`
echo $result
ps -Al | grep -c bash
You can try :
ps -ef | grep -cw [p]rocess_name
OR
ps aux | grep -cw [p]rocess_name
For e.g.,:
ps -ef | grep -cw [i]nit
Some of the above didn't work for me, but they helped me on my way to this.
ps aux | grep [j]ava -c
For newbies to Linux:
ps aux prints all the currently running processes, grep searches for all processes that match the word java, the [] brackets remove the process you just ran so it wont include that as a running process and finally the -c option stands for count.
List all process names, sort and count
ps --no-headers -A -o comm | sort | uniq -c
You also can list process attached to a tty
ps --no-headers a -o comm | sort | uniq -c
You may filter with:
ps --no-headers -A -o comm | awk '{ list[$1] ++ } END { for (i in list) { if (list[i] > 10) printf ("%20s: %s\n", i, list[i]) } }'
Following bash script can be run as a cron job and you can possibly get email if any process forks itself too much.
for i in `ps -A -o comm= --sort=+comm | uniq`;
do
if (( `ps -C $i --no-headers | wc -l` > 10 )); then
echo `hostname` $i `ps -C $i --no-headers | wc -l` ;
fi
done
Replace 10 with your number of concern.
TODO: "10" could be passed as command line parameter as well. Also, few system processes can be put into exception list.
You can use ps(will show snapshot of processes) with wc(will count number of words, wc -l option will count lines i.e. newline characters).
Which is very easy and simple to remember.
ps -e | grep processName | wc -l
This simple command will print number of processes running on current server.
If you want to find the number of process running on current server for current user then use -U option of ps.
ps -U root | grep processName | wc -l
change root with username.
But as mentioned in lot of other answers you can also use ps -e | grep -c process_name which is more elegant way.
ps aux | wc -l
This command shows number of processes running on the system by all the users.
For a specific user you can use the following command:
ps -u <username> | wc -l
replace with the actual username before running :)
ps -awef | grep CAP | wc -l
Here "CAP" is the word which is in the my Process_Names.
This command output = Number of Processes + 1
This is why When we are running this command , our system read thats "ps -awef | grep CAP | wc -l " is also a process.
So yes our real answer is (Number of Processes) = Command Output - 1
Note : These processes are only those processes who include the name of "CAP"

Resources