ps, pgrep, and pkill in Detail: Finding and Controlling Processes Precisely
AI generated
$
/etc
Linux
ps, pgrep, and pkill
Finding and controlling processes precisely

Everyone knows ps aux, but the procps toolset can do far more than one fixed default output. Knowing the format options of ps, the pattern matching of pgrep, and the namespace filters of pkill helps you find processes with precision and avoid the security pitfalls of an overly broad pattern.

9 min read Linux Process Management CLI

1. Beyond ps aux: custom format options

ps aux is the default call almost every admin types reflexively, but its fixed column selection is rarely optimal for a specific question. With ps -eo you can compose the output freely, with exactly the fields relevant to the current diagnosis, from process ID through memory usage to start time.

Especially useful is combining --sort with a custom field list, for instance to see the ten processes with the highest memory usage at a glance, without manually scanning through the entire process list. That saves valuable time during an acute memory issue on a Magento application server compared to scrolling through unsorted aux output.


# Custom field list: PID, user, CPU, RSS in MB, start time, command
ps -eo pid,user,pcpu,rss,lstart,cmd --sort=-rss | head -n 11

# Only processes of a specific user, sorted by CPU load
ps -u www-data -o pid,pcpu,pmem,etime,cmd --sort=-pcpu

2. Thread details and process tree view

By default, ps shows a process as a single line, even if it internally consists of multiple threads. With the -L or -T flag, individual threads are listed as separate lines, which helps when diagnosing multithreaded applications such as certain Elasticsearch or Java processes, to see which specific thread is causing high CPU load.

For the parent-child relationship between processes, ps -ef --forest provides an indented tree view that shows at a glance which PHP-FPM master started which workers, or which cron job spawned which child process, far clearer than a flat list with a PPID column.


# Show threads of a specific process individually
ps -L -p 28417 -o pid,tid,pcpu,comm

# Process tree as an indented tree structure
ps -ef --forest | grep -A5 php-fpm

3. pgrep: finding processes via pattern matching

pgrep searches the process list directly for process names or command line patterns and returns matching PIDs, without the detour through ps | grep and the extra process that comes with it, which can end up matching itself in the result. By default pgrep only checks the process name, with -f it instead matches the pattern against the full command line.

Additional filters such as -u for the user, -P for the parent process, and -x for an exact rather than partial name match make the search precise. Especially -x is often decisive in practice, since without it, processes whose name merely contains the pattern as a substring are matched too.


# Find PIDs of all php-fpm processes for a specific pool (search full command line)
pgrep -f "php-fpm: pool magento-prod"

# Only match exactly "redis-server" as process name, not e.g. "redis-server-old"
pgrep -x redis-server

# Processes of a specific user with detailed output (name + PID)
pgrep -u www-data -l

4. Namespace filters in pgrep and pkill

On hosts with containers or multiple PID namespaces, for instance in Mark-Shust-style Docker setups running several Magento instances, the host's process list quickly gets cluttered, since container-internal processes and host processes are all visible together. Newer versions of pgrep and pkill support the --ns flag to restrict the search to the namespace of a reference process.

That lets you search only within the PID namespace of a specific container, without accidentally hitting identically named processes in another container or on the host itself. If --ns is not available on a given distribution, the fallback is going through nsenter into the target container's namespace instead.


# Determine a container's reference PID
docker inspect --format '{{.State.Pid}}' magento-app-1

# Only search processes in the same PID namespace as this reference process
pgrep --ns 48213 -l php-fpm

5. pkill and the security pitfalls of overly broad patterns

pkill uses the same pattern matching logic as pgrep, but instead of returning a list of PIDs, it sends a signal directly to every match, SIGTERM by default. This exact combination of imprecise pattern and immediate effect makes pkill one of the most dangerous default commands in daily administration.

A classic pitfall: pkill -f magento on a host that, besides the Magento application, also runs an identically named backup script or a log rotation cron with 'magento' in its path, ends up terminating far more processes than intended. On multi-tenant hosts running several Magento instances, an overly broad pattern can even hit processes belonging to an entirely different customer installation.

The safe approach is always two-staged: first test the exact same criteria with pgrep, review the output manually, and only then apply the same pattern with pkill. On top of that, pkill should start with the gentler SIGTERM and only escalate to SIGKILL if there is no reaction, instead of going straight for -9.


# Test first: which processes would this pattern actually match?
pgrep -af "magento-prod-worker"

# Only terminate after manual review, gently with SIGTERM
pkill -f "magento-prod-worker"

# Escalate only if processes are still running after a short wait
sleep 5 && pkill -9 -f "magento-prod-worker"

6. Securing pkill with precise additional filters

To minimize the risk of an overly broad match, combining several filters is worthwhile instead of relying on a single, loosely defined pattern. -u restricts to a specific user, -P to child processes of a known parent, and --older or --newer filters by process age, which helps when cleaning up stuck old workers in a targeted way.

For PHP-FPM pools specifically, it is usually safer to reload the pool master in a controlled way via systemctl reload php8.4-fpm rather than terminating individual workers with pkill, because the master then handles a clean, controlled replacement of workers itself, instead of an externally sent signal disturbing the internal state of the pool.


# Only terminate processes of a specific user AND older than 2 hours
pkill -u www-data --older 7200 -f "worker.php"

# Terminate child processes of a known parent process specifically
pkill -P 28400

7. Comparison to systemctl and journalctl for systemd services

For any process managed as a systemd service, pgrep and pkill are fundamentally the wrong tool for control actions. systemctl restart, systemctl reload, and systemctl stop honor the stop sequence, timeout values, and any dependencies between services defined in the unit file, while a raw signal via pkill bypasses all of that.

If a systemd-managed process is terminated via pkill, systemd, depending on the restart policy, often interprets that as an unexpected crash and restarts the service automatically, which can produce confusing, seemingly unmotivated restarts. For pure observation, pgrep remains useful, but for actual control of systemd services, systemctl should consistently be used instead, complemented by journalctl -u <service> for the associated logs rather than manual process diagnosis.

The sensible scope for pgrep and pkill therefore stays limited to processes not managed by systemd, such as manually started scripts, legacy cron jobs, or debugging sessions where no unit file with a defined lifecycle exists.


# Correct for systemd-managed services: controlled restart
systemctl restart php8.4-fpm

# View the service's associated logs instead of manual process searching
journalctl -u php8.4-fpm -n 100 --no-pager

8. Best practices for production use

Before every pkill call, running a pgrep with the identical pattern as a check belongs into the workflow without exception, even under time pressure during an incident. Patterns should be formulated as specifically as possible, and when in doubt combined with additional filters like -u or -P rather than relying on a single, broadly matching name pattern.

For anything running under systemd, systemctl should consistently be used instead of pkill, since only that respects the stop sequence and any service dependencies defined in the unit file. ps -eo with a custom field list replaces, in most cases, several successive ps aux | grep calls and delivers exactly the information needed for the specific diagnosis from the start.

9. Combining continuous observation with watch and pgrep

For observing a slowly developing problem, such as a PHP-FPM pool gradually consuming more and more memory, combining watch with a targeted ps call is worthwhile, rather than retyping the command manually every few seconds. That lets you track in real time whether the number of workers or their memory usage is actually growing steadily.

pgrep -c, which returns only the count of matches instead of the individual PIDs, also works well for simple threshold checks in monitoring scripts, for instance to alert as soon as the number of running workers in a pool leaves an expected range, without needing to set up a more elaborate monitoring tool for it.

For a one-off but deeper snapshot of all processes of a specific user together with the full command line, ps -u www-data -o pid,cmd --no-headers serves as a good basis for further scripts, for example to automatically derive a list for pgrep or targeted kill calls, instead of manually post-processing raw data.


# Watch a pool's memory usage live every 2 seconds
watch -n 2 'ps -eo pid,rss,cmd | grep "pool magento-prod" | grep -v grep'

# Just the match count for a simple threshold check
pgrep -cf "pool magento-prod"
Tool Main Purpose Risk if Misused Better Alternative Under systemd
ps -eo/--sort Format and sort the process list precisely Low, read-only display Not applicable
pgrep Find processes by pattern/namespace/user Low, no effect on processes Not applicable
pkill Send a signal to every pattern match High, an overly broad pattern hits the wrong processes systemctl stop/restart/reload
kill -9 directly Immediate hard termination without cleanup High, no clean shutdown, potential data loss systemctl with a defined timeout

Mironsoft

Server administration, Docker hosts, and performance tuning

Linux servers nobody on the team really understands anymore?

We handle setup, hardening, and performance tuning of Linux servers and Docker hosts for Magento deployments, documented and traceable instead of grown and unclear.

Server Audit

Review the existing server configuration for security gaps and performance bottlenecks.

Docker Host Setup

Set up and secure production-ready Docker environments for Magento cleanly.

Monitoring & Tuning

Measure resource usage and tune systemd, kernel, and services with purpose.

10. Summary

ps/pgrep/pkill

Audience

Admins finding and controlling processes precisely instead of relying on plain ps aux

Core command

pgrep -f 'pattern' before every pkill to verify

Combine with

additional filters -u, -P, --older for precise targeting

Biggest pitfall

pkill with an overly broad pattern on a multi-tenant host

11. FAQ: ps/pgrep/pkill

1Why is pkill more dangerous than pgrep?
pgrep only outputs a list of matching PIDs for review, while pkill immediately sends a signal to every match. An overly broad pattern can therefore make pkill terminate far more processes than intended.
2How do I safely test a pkill pattern beforehand?
With pgrep using the identical pattern, ideally with the -a or -l flag for readable output. Only after manually reviewing the match list should the same pattern actually be passed to pkill.
3What does the -f flag do in pgrep and pkill?
Without -f, only the plain process name is checked, with -f the full command line including arguments is matched instead. For PHP-FPM pools with the pool name in the command line, -f is almost always necessary for precise filtering.
4How do I find only processes of a specific Docker container?
Via the --ns flag of pgrep and pkill, combined with the host PID of the container's main process from docker inspect. Alternatively, nsenter into the target container's namespace also works.
5Why should I use systemctl instead of pkill for systemd services?
systemctl respects the stop sequence, timeouts, and service dependencies defined in the unit file. A raw signal via pkill bypasses that and, depending on the restart policy, can even trigger an unexpected automatic restart by systemd.
6How do I sort ps output by memory usage?
With ps -eo pid,user,rss,cmd --sort=-rss, processes are sorted descending by RSS memory usage, combined with head the list can be limited to the most relevant entries.
7What is the difference between -x and -f in pgrep?
-x requires an exact match of the process name instead of a substring match, -f instead extends the search to the full command line. Both flags solve different precision problems and can be combined.
8Can pkill accidentally hit processes belonging to a different customer instance?
Yes, on multi-tenant hosts running several Magento instances, an overly general pattern like magento can hit processes of a completely different installation. Precise patterns with a full path or pool name are essential here.
9Does ps show individual threads by default?
No, by default ps shows a process as a single line regardless of its number of threads. With the -L or -T flag, individual threads can be listed as separate lines.
10Should I start pkill with SIGKILL instead of SIGTERM?
No, the safe workflow always starts with the default signal SIGTERM, to give the process a chance to shut down cleanly. Only if there is no reaction after a short wait should you escalate to SIGKILL with -9.