Confusion with PS

Hello All,

I have a problem in counting number of process getting run with my current script name..

Here it is

ps -ef | grep $0 | grep -v grep

This display just one line with the PID, PPID and other details when i print it in the script.

But when I want to count the numbers in my script , just like below, it comes out as 2... Whereas only one process is running..

count=$(ps -ef | grep $0 | grep -v grep | wc -l)
echo $count

My mind completely gone blank, help me here..
Help me how I will get my script to print the correct number of Process running with its name. Thanks.

Just one question. from where you are getting $0 ?

Thats my Script name, this command line is placed inside my script...

If I understand correctly, he runs these commands from inside a script.

However, see my script, named "file":

#!/bin/bash
echo $0
ps axu |head -n 1 # this is to see ps headers
ps axu | grep $0 | grep -v grep | tee /dev/tty |wc -l
ps axu | grep $0 | grep -v grep  |tee /dev/tty |wc -l

If I run it, most of the time I get:

lem@biggy:/tmp$ ./file
./file
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
lem      25757  0.0  0.0  18584  1432 pts/3    S+   11:44   0:00 /bin/bash ./file
1
lem      25757  0.0  0.0  18584  1432 pts/3    S+   11:44   0:00 /bin/bash ./file
1

Very few times I get instead:

lem@biggy:/tmp$ ./file
./file
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
lem      25770  0.0  0.0  18584  1428 pts/3    S+   11:44   0:00 /bin/bash ./file
1
lem      25770  0.0  0.0  18584  1428 pts/3    S+   11:44   0:00 /bin/bash ./file
lem      25779  0.0  0.0  18584   432 pts/3    R+   11:44   0:00 /bin/bash ./file
2

The first ps always gives me one process, the second ps seldom gives two.
--
Bye

I found out the problem :slight_smile: Since we give wc -l, this gets a new line. And hence that has got counted in it.

I changed that to

ps -ef | grep $0 | grep -cv grep

Now it works cool. Thanks Pamu and Lem.

Sadly, i don't think so. :frowning:
--
Bye

All of the problems witnessed above are the result of the shell forking to create new processes to run a pipeline: ps, grep, wc, another shell for the command substition (in the case of the original post). All of these processes initially begin as a new shell with the same name, $0, as the parent shell.

If ps scans the process list before any of these shells have had a chance to exec and become the utility it will become, the result is multiple instances of $0.

The solution is trivial and widely available: pgrep

Your analysis is incorrect. You're just getting lucky with timing. In your original wc version, you were unlucky with timing. Nothing has been fixed.

The reason pgrep works reliably is because it's only one command and it doesn't run until after the shell that was forked to create it has exec'd.

Unless the system lacks pgrep and pkill , there's no need to resort to the ps ... | grep/awk ... silliness.

Regards,
Alister

1 Like

Hey Alister,

Yes I WAS lucky to get that desired ouput. After a while, I found out am unlucky.. It again started creating that mess. Also the problem is my system doesn't contain pgrep :frowning: I found out another way to accomplish my result.

If there is any other way that we can acquire the result with grep, wc or other silly commands, please post here..

Exactly which version of which operating system you are using?

It will help to know exactly what you're trying to accomplish. Show us the shell script and explain what it's supposed to do.

Regards,
Alister

Hint:

ps -ef >tmpfile
count=$(grep $0 tmpfile |grep -v grep |wc -l)
...

--
Bye

EDIT: LOL, obviously in this case there's no need to purge "grep" strings from grep output.

@Lem: you are simply awesome.

@Alister: I have a cron which runs my script every 1 minute. If any error identified by my script, it runs another program which takes a while say 4 mins. Until it gets completed, my Cron should not allow the Script to run on the next minute.. So i thought of counting the number of PS of that script name will fix that problem. Thanks to Lem for that Solution.

What I have built is as below:

pd=$(head -1 pid.check)
ps -ef | grep $pd | grep -v grep 
if [ $? -eq 0 ]; then
exit 0
fi

pid1=$$
echo "$pid1" > pid.check

Shout me if the above fails at any condition, I will correct my code. Thanks

Needs a "first time" condition. Also, if you know the pid just look for the one pid. You can dump the output from ps as you only need to know if the process is still running.

# Has previous script finished?
if [ -f pid.check ]
then
       pd=$(head -1 pid.check)
       ps -fp $pd 1>/dev/null
       if [ $? -eq 0 ]
       then
              exit 0
       fi
fi
# Record pid of current script
pid1=$$
echo "$pid1" > pid.check
### PROCESSING GOES HERE

It would be better to specify a directory (e.g. /var/tmp) for pid.check file or it will be created in the home directory of the owner of the crontab.