1

Here's my script:

$ cat count_tomcat.sh 
ps -ef | grep tomcat| wc -l
$ ./count_tomcat.sh 
2

Now with the watch command it has different results:

$ watch ./count_tomcat.sh


Every 2.0s: ./count_tomcat.sh                                                                                                                                                                                Fri Oct 15 16:50:43 2021

5

2 Answers 2

2

Just run:

watch -x pgrep -c -f tomcat

To regularly get a count of processes whose command line contains tomcat.

Or

watch -x pgrep -c -x tomcat

For the processes whose name (not command line; like in the output of ps -e wrt ps -ef) is tomcat.

Or:

watch -x pgrep -c -u tomcat

For the count of processes running as user tomcat (as it's not clear what column of the output of ps -ef you intend to match).

With -x, at least for procps-ng' implementation of watch, we skip running a shell but execute the command directly.

Note that pgrep -f tomcat will not report itself (even though its command line contains tomcat), but it would count the watch command and without -x added to watch, possibly the sh -c 'pgrep -f tomcat' that watch invokes to parse that command line if your sh implementation doesn't optimise out the fork for the last command.

watch -x pgrep -cf '[t]omcat'

Would avoid that as the [t]omcat pattern doesn't match itself.

(without -x, that would have to be:

watch 'pgrep -cf "[t]omcat"'

as [x] is also a shell globbing operator so needs to be escaped both for your shell and the shell that watch runs)

Of course, it would also match on a process that runs vi tomcat.conf or atomcatalog. Matching processes based on command line is very brittle. With pgrep you can add more options to refine the filter and limit the risk of identifying the wrong processes.

On modern Linux systems, you should be able to rely on control groups, or query systemd for that information if tomcat has properly been setup as a service.

1

Turns out when you run a script "the normal way" ./count_tomcat.sh it doesn't spawn a new bash process, it just runs it in the current bash process. So no new entry for that script in ps output.

When you run it via watch, it spawns a whole new bash process, with your script as a parameter. So now script shows up (itself) in the ps output. So be aware with ps and watch.

Second issue: when running the ps command in a "normal" bash script, it knows it's being "run as a script" and does full output.

When running the ps command within a script being run by the watch command, somehow ps doesn't know that it's not in a TTY environment (i.e. in a script), so it truncates the output size to exactly 80. Something's not right there. Fix: use ps -ww (infinite width) iff run within watch. Maybe there are other ways. Weird.

Helpful is to add set -x to script.

3
  • 2
    That's not correct; running a script with ./scriptname does start a new subprocess. Try removing the | wc -l so you can see what processes are actually being seen. (BTW, this sort of confusion is exactly why pgrep is preferred over ps | grep.) Commented Oct 15, 2021 at 17:44
  • OK it is a subprocess that doesn't contain the script name in its ps output?
    – rogerdpack
    Commented Oct 15, 2021 at 17:49
  • 1
    Apparently not. This seems to be a side effect of how bash handles scripts that don't start with a shebang line (e.g. #!/bin/bash). Try making a script that contains just a single line: echo "running as process ID $$"; ps, make it executable, and run it with ./scriptname. Compare with running the same command in your interactive shell, and you'll see that the script lists an extra "bash" process. Now, add a shebang to the script and try again. You can also try running it with source scriptname, and you'll see that this method does run it in the same shell. Commented Oct 15, 2021 at 18:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .