ps -f
gives an output like:
chazelas 11042 10528 1 08:49 ? 00:00:03 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 7847 -prefMapSize 699608 -parentBuildID 20200720193547 -appdir /usr/lib/firefox/browser 10528 true tab
Doing grep "$1"
to return the lines for a given process name is wrong on many accounts:
- that fails if
$1
starts with -
. You need grep -e "$1"
or grep -- "$1"
. You should really get into the habit of using the end-of-options delimiter when passing arbitrary data to commands.
grep
takes a regexp pattern to match on (that's the re
in grep
). So grep a.py
would match on aspy
for instance. You can use grep -F
to search for substrings instead.
ps -f
does not report the process names but the process arguments (including argv[0]
which by convention is generally a path to the command).
- you're grepping for regexp/substrings, without restricting where within the lines it matches. So above for
$1
== as
for instance, it would match on the as
in chazelas
. Or it could match on the other arguments than argv[0]
.
grep | wc -l
is grep -c
.
Here, there is a (non-standard but very common) command to match processes by name (or other criteria for that matters): pgrep
pgrep -xc -- "$1"
Would c
ount the processes whose name (like that reported by ps
without -f
) matches ex
actly the regexp in $1
. With -f
, pgrep
matches on the full list of arguments (as reported by ps -f
) instead of the process name.
That leaves the problem of process names containing regexp operators (like the .
mentioned above). Unfortunately, pgrep
doesn't have a -F
option to do a string comparison instead of regexp match, so you'd need to escape the regexp operators in there.
Another option is to tell ps
to only report the process names and then use grep -xF
to do ex
act F
ixed-string comparison:
ps -Ao comm= | grep -Fxce "$1"
Replace comm
with args
to print the list of arguments (possibly truncated though, some ps
implementations allow one or more -w
to raise the line length limit) instead of process name.
In any case, any user can create any process with any name and with any list of arguments, so finding processes by name is quite brittle. Anybody can trick you into thinking your process is there by starting one with the same name and same list of arguments running a completely different command.
It's generally better to check for the availability of services that your process is providing or hold on some resource it's currently using.
In some cases, you can add other criteria to your search such as effective uid (-u
in pgrep
), or the path of the executable it is currently running.
On Linux and with zsh
:
pids=(/proc/<->(Nnu[chazelas]e['[[ $REPLY/exe -ef /usr/bin/sleep ]]']:t]))
Would store in $pids
the ids of the processes that are running code in the /usr/bin/sleep
file as the chazelas
user for instance and you can use if (($#pids > 0)); then...
to check that that list is not empty. (replace /usr/bin/sleep
with =sleep
or $commands[sleep]
for searching the sleep
command in $PATH
).
More generally, it's much better to rely on your service manager to manage services and processes. Modern ones such as systemd
will provide facilities to do that reliably.