5

Here is a very strange question about using pgrep to search which shell processes are running the same script as the current one.

Here is the test script named test.sh

#!/bin/bash

full_res=pgrep -a -l -f 'test\.sh'

res=$(pgrep -a -l -f 'test.sh' | cat)

echo "short result is $full_res"

echo "weird result is $res"

With output being

sh test.sh &
[1] 19992
➜  logs short result is 19992 sh test.sh
weird result is 19992 sh test.sh
19996 sh test.sh

[1] + 19992 done sh test.sh

I don't know where the 19996 sh test.sh comes from, especially when using a pipe to cat. I believe it might be a bug to pgrep implementation.

Looking forward to some reasonable explanation

Thx,

Balin

2 Answers2

9

When you created the pipeline using backticks or $(...) a subshell is created which is an exact copy of the original bash shell you called.

At the point you're doing the pgrep what you actually have is this:

bash test.sh
  └─bash test.sh
      └─ pgrep -f test.sh
      └─ cat

So pgrep is doing what you asked it to.

You can simulate this behaviour like this.

#!/bin/bash
echo mypid $$
$(sleep 60 | sleep 60 | sleep 60)

Run the process in the background, using the pid it spat out, inspect it with pstree.

$ ./test.bash 
mypid 335153
^Z
[1]+  Stopped                 ./test.bash
$ bg
[1]+ ./test.bash &
$ pstree -p 335153
test.bash(335153)───test.bash(335154)─┬─sleep(335155)
                                      ├─sleep(335156)
                                      └─sleep(335157)
Matthew Ife
  • 24,261
5

From Pipelines in the bash manual:

Each command in a multi-command pipeline, where pipes are created, is executed in its own subshell, which is a separate process

Tangentially, this is why this won't work:

date | read theDate
echo "$theDate"

because the read command runs in a subshell, so the theDate variable is populated in the subshell, not in the current shell.