Confirmation About Pgrep Returning Itself

Confirmation about pgrep returning itself

The answer is already in the comments to my question, but I figure I'll close this out with an official answer.

The piece of information I was missing is that

When bash is invoked as sh it behaves as a POSIX sh, not bash. – Jörg W Mittag Jan 23 at 23:31

So yes, pgrep was behaving normally. But when you call it from a Ruby script via backticks, you still need to filter out 'pgrep'

pgrep {process_name} | wc -l returning wrong results

So at first we do ./test.sh from the terminal. So we have a single process with process name test.sh.

process_count=`pgrep 'test.sh' | wc -l`

The command substitution invoked by backticks runs a subshell. The subshell is a separate process and has the same process name test.sh. So there are now two processes with different pids that are having the process name test.sh. Thus pgrep returns two lines.

This could be for example inspected with:

process_count=$(
ps -e -o pid,comm | grep 'test.sh' >&2
echo BASHPID=$BASHPID \$=$$ >&2
pgrep 'test.sh' | wc -l
)

with outputs on stderr:

 495463 test.sh
495466 test.sh
BASHPID=495466 $=495463

The 495466 is the pid of the subshell and 495463 is the pid of the parent shell process.

When you do:

pids=`pgrep 'test.sh'`;

this outputs a single pid. This is because bash has an optimization, that on specific circumstances (ex. no traps) when only one process is left to execute in a shell, it optimizes and doesn't call fork()+exec() instead it calls just exec, because there will be no next process to run, so it can just exit. The inner subshell with the process name test.sh exists only for a short moment, the subshell detects that there is only a single command to run, so it skips fork(), just executes exec("pgrep") and becomes a process with process name pgrep. That is why you do not see another pid in this case.

Notes: Please do not use backticks `. Use $(...) instead.

Extra: More subshells! The following

echo "$(echo "$(echo "$(pgrep 'test.sh' | wc -l)")")"
# would output 4

pgrep command not returning PID

Normally pgrep applies the search pattern to process names. The process name in this case is python and not motion_sensor.py. If you want to grep for the full path rather than just the process name you need to pass -f:

pgrep -u www-data -f motion_sensor.py

Check man pgrep

pgrep returning true in makefile but not in shell

I think it's finding the command coming from the makefile itself. make is executing something like:

/bin/bash -c 'if pgrep -f askdfkasdfj ; then kill $$(pgrep -f askdfkasdfj); fi'

This contains askdfkasdfj in the -c argument, so it matches.

But I'm not sure why this didn't happen as well when you used ps aux | grep.

bash script variable substitution problem

It's happening because at the time your script is running it also
contains mypgrm in its name like that:

bash ./test.sh mypgrm

and therefore is reported by pgrep -f. You can filter it out like
that:

pgrep -f "$1" | grep -v "^$$\$"

or use a little trick and pass a name of the program in the form that
wouldn't be visible to pgrep:

./test.sh '[m]ypgrm'

Difference between pgrep in sh and bash

It's probably a timing issue and pgrep finds itself, as you're issuing it with -f and novalidname is present in the command line. Try with -l to confirm.



Related Topics



Leave a reply



Submit