For example:
$ cat foo.sh
#!/usr/bin/env bash
while true; do sleep 1 ; done
$ ./foo.sh &
$ pgrep foo.sh
$
Contrast with:
$ cat bar.sh
#!/bin/bash
while true; do sleep 1 ; done
$ ./bar.sh &
$ pgrep bar.sh
21202
The process started by env bash
shows up in the output of ps aux
as:
terdon 4203 0.0 0.0 26676 6340 pts/3 S 17:23 0:00 /bin/bash
while the one started with /bin/bash
shows as
terdon 9374 0.0 0.0 12828 1392 pts/3 S 17:27 0:00 /bin/bash ./bar.sh
which probably explains why it the first is not being caught by pgrep
. So, questions are:
- Why does the name of the script not show up when called through
env
? - Does
pgrep
simply parse the output ofps
? - Is there any way around this so that
pgrep
can show me scripts started viaenv
?
Best Answer
Q#1
From the shebang wikipedia article:
So this means that the name of the script is what's known by the kernel as the name of the process, but then immediately after it's invoked, the loader then execs the argument to
#!
and passes the rest of the script in as an argument.However
env
doesn't do this. When it's invoked, the Kernel knows the name of the script and then executesenv
.env
then searches the$PATH
looking for the executable to exec.It is then
env
that executes the interpreter. It knows nothing of the original name of the script, only the Kernel knows this. At this pointenv
is parsing the rest of the file and passing it to interpreter that it just invoked.Q#2
Yes, kind of. It's calling the same C libraries that
ps
is making use of. It's not simply a wrapper aroundps
.Q#3
I can see the name of the executable in the
ps
output.In which case you can use
pgrep -f <name>
to find the executable, since it will search the entire command line argument, not just the executable.References