ps command in linux - linux

I'm a newbie to unix-like. And I met a weird issue that I really cannot find answers by searching.
#!/bin/bash
me=`basename "$0"`
echo $(ps -e | grep "$me" | wc -l)
ps -e | grep "$me" | wc -l
After executing that bash script, the echo shows me 2, and ps just shows me 1 which is what I want. How can this happen? Why echo shows me an extra process?

As Charles Duffy pointed out, $() creates a subshell. That answers my question. Apparently I still have a lot to learn. Thanks for all the help.

As noted by a comment by Cyrus; this script:
me=$(basename $0)
ps -ef |grep $me
when launched with "./ps.sh", prints:
auser#pc:/tmp$ ./ps.sh
auser 4425 4422 0 08:42 pts/3 00:00:00 grep ps.sh
auser#pc:/tmp$
No subshells are involved here, it is the grep(1) itself that is listed by ps(1). The same script, launched with "bash ps.sh" outputs:
auser 4426 3946 0 08:44 pts/3 00:00:00 bash ps.sh
auser 4429 4426 0 08:44 pts/3 00:00:00 grep ps.sh
This is the result the OP gets, even without subshells. Even more explicit:
auser#pc:/tmp$ ps -ef |grep grep
auser 4467 3946 0 08:49 pts/3 00:00:00 grep grep

although you are creating a sub shell by using $() you can grep this out by using grep -v grep.
So:
$(ps -e | grep "$me" | grep -v grep | wc -l)
which will return 1 instead of 2

Related

How to get pid by unique process name in linux?

I have two java program running on server MyProgram and MyProgramTest.
ps -ef | grep -i java
root 505 17711 0 16:54 pts/4 00:00:00 grep -i MyProgram
root 16450 16448 99 16:46 pts/4 00:07:29 java MyProgram
root 16473 16471 99 16:46 pts/4 00:07:29 java MyProgramTest
I want to search there pid using below commands
ps ax | grep -v grep | grep MyProgram
It should give me PID 16450 but it is giving both
16450 pts/4 Sl 9:19 java MyProgram
16473 pts/4 Sl 9:19 java MyProgramTest
Expected Output :
16450 pts/4 Sl 9:19 java MyProgram
How to get PID by Unique Process Name in linux ?
ps ax | grep -v grep | grep -w "MyProgram"
or
ps ax | grep -v grep | grep "\MyProgram\b"
You can use,
ps ax | grep -v grep | grep -w MyProgram
-w for Whole Word Match. However, It will also match things like MyProgram or MyProgram Hello.
To avoid tricks like grep -v grep it is better to use pgrep:
pgrep --exact MyProgram
Suffix $, ie; the process name ends with "MyProgram",
$ ps -ef |grep MyProgram$

Killing a process in linux

I am trying to kill a process in linux
ps -aux
root 14074 0.0 0.4 6586120 67452 pts/0 Sl 22:45 0:01 java -cp target/cronscheduler-1.0-SNAPSHOT.jar com.cronscheduler.QuartzMain
Kill the process in the stop script using the below command
ps aux | grep "java -cp target/cronscheduler-1.0-SNAPSHOT.jar com.cronscheduler.QuartzMain" | \
grep -v grep | awk '{print $2}' | xargs kill -9
Issue is this command works fine when cronscheduler.QuartzMain is running. But when this process is already killed then the above command throws error
Usage:
kill [options] <pid|name> [...]
Your inputs on removing the errors are appreciated
pkill can search through the complete command line. Try
pkill -9 -f 'java -cp target/cronscheduler-1.0-SNAPSHOT.jar com.cronscheduler.QuartzMain'
Your command may create errors, because it sends more than the pid (the complete line from ps) to kill.
One of the solution I found was to redirect the error message :
cat /etc/*.conf 2> /dev/null
ps aux | grep httpd
httpd 3486 0.0 0.1 4248 1432 ? S Jul31 0:00 /usr/sbin/httpd -f /etc/httpd/httpd.conf
# kill 3486
OR
$ sudo kill 3486
Please try below this will help in clearing the child process id's as well.
for i in `ps -ef| grep "java -cp target/cronscheduler-1.0-SNAPSHOT.jar com.cronscheduler.QuartzMain" | grep -v grep | awk '{print $2}'`
do
ptree $i|awk '{print $1}' >>pids.txt
done
for i in $(cat pids.txt)
do
kill -9 $i
done

Issue finding the process id from shell scipt

mySample.sh
pid=$(ps -Af | grep $1 | grep -v grep | awk ' { print $2 } ');
echo $pid
The above command is printing and killing the temporary process that was created for grep
Even though i do not have any process running with Abcd,
This is printing pid
Any ways to ignore it,
iam actually ignoring it using grep -v, still...
./mySample.sh Abcd
6251 6378 6379
Any Issue in fetching the process id.?
Basic command line output is below,After running a process with name Acc_Application_One
[root#localhost Desktop]# ps -Af | grep Acc
root 6251 2758 0 16:16 pts/1 00:00:00 ./Acc_Application_One
root 7288 2758 0 16:57 pts/1 00:00:00 grep Acc
Changed mySample.sh
pgrep -fl "$1"
And the output is
[root#localhost Desktop]# mySample.sh Acc_Application_One
6251 7289
To kill a process with the pattern anywhere in command line use pkill -f:
pkill -f "$1"
As per man pkill:
-f Match the pattern anywhere in the full argument string of the process instead of just the executable name.
Similarly you can use pgrep -f "$1" to list the process id of the matching process.
Try something much simpler:
pid=$(pgrep "$1")
And if you want to kill it:
pkill "$1"
The problem will become clear when you remove the awk: mySample.sh will have Abcd as well.
ps -Af | grep " $1" | grep -Ev "grep|$0" | awk ' { print $2 } '
Changed mySample.sh script with below code
And This is just fetching the processId using the parameter sent
and killing it
pid=$(pgrep -fl $1 | grep -v '[k]ill_script'| awk ' { print $1 } ')
echo $pid
if [[ -n ${pid} ]]; then
echo "Stopping Acc Application $1 with pid=${pid}"
kill -9 ${pid}
fi
Thanks

bash process substitution can't work fine with tee

The real thing I want to do is like ps -ef|head -n1 && ps -ef|grep httpd. The output should be something like this.
UID PID PPID C STIME TTY TIME CMD
xxxxx 6888 6886 0 16:49 pts/1 00:00:00 grep --color=auto httpd
root 10992 1 0 13:56 ? 00:00:00 sudo ./myhttpd
root 10993 10992 0 13:56 ? 00:00:00 ./myhttpd
root 11107 10993 0 13:56 ? 00:00:00 ./myhttpd
root 12142 10993 0 14:00 ? 00:00:00 ./myhttpd
root 31871 10993 0 15:03 ? 00:00:00 ./myhttpd
But I hate duplicates. So, I want ps -ef to appear only once.
Considering bash process substitution, I tried ps -ef | tee > >(head -n1) >(grep httpd), but the only output is
UID PID PPID C STIME TTY TIME CMD
However, ps -ef | tee > >(head -n1) >(head -n2) can work fine in the following way
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:36 ? 00:00:00 /sbin/init
UID PID PPID C STIME TTY TIME CMD
Can anyone help me ?
You can do head and grep on the same stream.
ps -ef | (head -n 1; grep '[h]ttpd')
It might be marginally more efficient to refactor to use sed:
ps -ef | sed -n -e '1p' -e '/[h]ttpd/p'
... but not all sed dialects deal amicably with multiple -e options. Perhaps this is more portable:
ps -ef | sed '1b;/[h]ttpd/b;d'
Also note the old trick to refactor the regex so as not to match itself by using a character class.
This can be achieved simply with pgrep and ps.
ps -fp $(pgrep -d, -o -f httpd)
use AWK
ps -ef | awk 'NR==1 || /httpd/'
print out 1st line or any line contains "httpd"
or use sed
ps -ef | sed -n '1p;/httpd/p'
ps -f -C httpd --noheaders | head -n1

Inconsistency between perl grep and cli grep

I am doing the following:
#!/usr/bin/perl
use strict;
use warnings;
my $proc = `ps -ef|grep -c myscriptname`;
print $proc;
This prints 2 when I run it inside the script.
ps -ef|grep -c myscriptname on the command line just shows: 1
Why?
same for my $proc = qx/ps -ef|grep -c myscriptname/
UPDATE
To be clear I run this snippet from somerandomscript.pl
Update 2
Following the advice of edorqui I remove -c getting:
12013 15777 15776 0 14:11 pts/6 00:00:00 sh -c ps -ef | grep myscriptname
12013 15779 15777 0 14:11 pts/6 00:00:00 grep myscriptname Argument "12013 15777 15776 0 14:11 pts/6 00:00:00 sh -c ps..." isn't numeric in numeric gt (>) at somerandomscript.pl line 8
from inside the script
The ps -ef command is showing the grep itself.
To skip this behaviour, try grepping for a regex condition that does not match the grep itself:
ps -ef | grep myscript[n]ame
or whatever similar can make it:
ps -ef | grep myscriptnam[e]
Explanation
If you run a sleep command in the background:
$ sleep 100 &
[1] 9768
and then look for it with ps -ef:
$ ps -ef | grep sleep
me 9768 3673 0 14:00 pts/6 00:00:00 sleep 100
me 9771 3673 0 14:00 pts/6 00:00:00 grep --color=auto sleep
You get two lines: the process itself and the grep command looking for it. To avoid it and show just the process itselves, we can either:
$ ps -ef | grep -v grep | grep sleep
or use a regex in the code so that the grep process is not matched:
$ ps -ef | grep slee[p]
me 9768 3673 0 14:00 pts/6 00:00:00 sleep 100
because line
me 9771 3673 0 14:00 pts/6 00:00:00 grep --color=auto sleep
does not match in grep slee[p].
See explanation in a related topic.
I suposse your perl script is named "myscriptname".
When you run this script, you have a new process (perl myscriptname.pl), and it's showed by the ps -ef command. The other one is related to the grep command (it has the text you are looking for)
#fedorqui's answer is right on -- the grep is matching its own invocation in the process table, and perhaps that of its parent shell, too, though timing issues mean this does not always happen from the CLI.
However, another approach, avoiding grep in favor of perl, would be:
my $count = () = qx(ps -e -o cmd) =~ /myscriptname/mg;
# Now $count tells you the number of times myscriptname appears in the process table
See this answer for why the empty parens are used above. Note, too, that you don't need the full ps output (-f), you just want to match on the command name (-o cmd).
Take a look at the pgrep and the pkill commands. These are standard Linux commands are are way easier to use than trying to do a ps and then a grep.
Also, if you do use ps, take a look at the -o options. These let you display the columns you want, and give you a way to strip out the heading.

Resources