opscape

Processes and jobs

pgrep

Print the PIDs of processes whose name (or full command line) matches a pattern, with filters by user, parent and age.

pgrep [OPTION...] PATTERN

12 of 12 examples run in Debian 13.7 on 2026-10-31 · procps 2:4.0.4-9 · manual: pgrep(1)

pgrep answers "what is the PID of that process?" without the ps aux | grep ... | grep -v grep | awk '{print $2}' dance. It matches an extended regular expression against each process's name, which is the program name truncated to 15 characters (what ps -o comm shows), and prints one PID per line. With -f it matches against the whole command line instead, which is what you need for scripts run by an interpreter (python3 app.py is named python3).

Filters narrow the match: -u by user, -P by parent PID, -n/-o newest or oldest only, -x exact name. -l and -a add the name or command line to the output, -c counts. The exit status is 0 if anything matched and 1 if nothing did, so pgrep -x nginx >/dev/null is a clean "is it running?" test.

pkill is the same program with the same matching rules, sending a signal instead of printing. Try a pattern with pgrep -a first, then swap in pkill. pgrep never lists itself, but with -f it can match the shell or script that runs it, because that command line contains the pattern too. The examples show this and the fixes.

Examples

Find the PIDs of a program

sleep 300 & sleep 600 &
pgrep sleep
output
1735
1736

One PID per line, oldest first. The pattern is a regular expression matched anywhere in the process name, so pgrep sle would also match.

Show the command line next to each PID

sleep 300 & sleep 600 &
pgrep -a sleep
pgrep -l sleep
output
1738 sleep 300
1739 sleep 600
1738 sleep
1739 sleep

-a prints the full command line, -l just the process name. Use -a to check what a pattern catches before you hand it to pkill.

Match the name exactly

sleep 300 &
pgrep -x slee; echo "slee: exit $?"
pgrep -x sleep
output
slee: exit 1
1742

-x requires the whole name to match, so slee finds nothing (exit status 1) and sleep finds the process. Without -x, pgrep ssh also matches sshd and ssh-agent.

Count matching processes

sleep 300 & sleep 600 & sleep 900 &
echo "$(pgrep -c sleep) sleep processes"
output
3 sleep processes

-c prints the number of matches instead of the PIDs. Handy for "how many workers are running" checks.

Test whether a program is running

sleep 300 &
if pgrep -x sleep >/dev/null; then echo "sleep is running"; fi
pgrep -x nginx >/dev/null || echo "nginx is not running"
output
sleep is running
nginx is not running

The exit status is 0 when at least one process matched and 1 when none did, so the output can be discarded and the test used directly in if or ||.

Match against the full command line

python3 -c 'import time; time.sleep(300)' &
sleep 0.2
pgrep -a python3
pgrep -f 'time.sleep' >/dev/null && echo "found by command line"
output
1 python3 /opt/runner/run.py
1754 python3 -c import time; time.sleep(300)
found by command line

The process name is python3 whatever script it runs, so to find a particular script you need -f. This sandbox's own runner is also a python3 process (PID 1), which is why matching by name alone catches two.

Why pgrep -f can match your own shell

sleep 300 &
pgrep -af 'sleep 300'
kill %1
output
1758 /bin/bash -c sleep 300 & pgrep -af 'sleep 300' kill %1
1759 sleep 300

Besides the sleep, -f matched the bash -c shell running this example, because its command line contains the text sleep 300. A script doing pkill -f myjob can kill itself the same way. The next example shows two fixes.

Exclude your own shell from -f matches

sleep 300 &
pgrep -A -af 'sleep 300'
kill %1
output
1762 sleep 300

-A (--ignore-ancestors, new in procps 4) leaves out pgrep's own parent, grandparent and so on, so the shell running the command is no longer matched. On older systems, the bracket trick does the same job when the searching command line is not also the one that started the process: pgrep -f '[s]leep 300' still matches sleep 300, but its own command line contains [s]leep, which the pattern does not match.

Filter by user, newest or oldest

sleep 300 & sleep 301 & sleep 302 &
pgrep -u dev -n -a sleep
pgrep -u dev -o -a sleep
output
1767 sleep 302
1765 sleep 300

-u restricts to an effective user (name or UID, comma-separated). -n keeps only the newest match and -o the oldest; both are useful when several copies run and you want the one you just started.

Find the children of a process

(sleep 300 & sleep 400 & wait) &
sleep 0.2
pgrep -a -P $!
output
1772 sleep 300
1773 sleep 400

-P PPID matches processes whose parent is PPID; with no pattern it lists all of them. Here that is the two sleep processes started by the background subshell.

Get PIDs on one line for another command

sleep 300 & sleep 600 &
pgrep -d, sleep
ps -o pid,etime,args -p "$(pgrep -d, sleep)"
output
1775,1776
    PID     ELAPSED COMMAND
   1775       00:00 sleep 300
   1776       00:00 sleep 600

-d, joins the PIDs with commas, which is the list format ps -p and top -p accept.

A name longer than 15 characters never matches

pgrep my-long-worker-name
explain
outputexit 1
pgrep: pattern that searches for process name longer than 15 characters will result in zero matches
Try `pgrep -f' option to match against the complete command line.

The kernel stores only the first 15 characters of a process name, so a longer pattern can never match by name. procps warns about it; use -f to match the command line instead.

Common pitfalls

  • pgrep -f pattern matching the shell or script that runs it (and pkill -f killing it). Use -A, the [x]yz bracket trick, or a more specific pattern, and always look with pgrep -af first.

  • Forgetting that the pattern is an unanchored regex: pgrep ssh matches sshd, ssh-agent and ssh. Use -x for an exact name or anchor with ^ssh$.

  • Matching scripts by name. A Python, Node or bash script's process name is the interpreter (python3, node, bash); use -f with the script's file name.

  • Expecting a match for names over 15 characters. The kernel truncates comm; pgrep -f sees the full command line.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • -a means different things. On Linux (procps) it prints the full command line; on FreeBSD and macOS it includes pgrep's ancestors in the matches, which those systems exclude by default. To print command lines there, use pgrep -lf.

  • The core options -f, -l, -x, -u, -n, -o, -P and -d work on Linux, macOS and FreeBSD. The long -- forms and procps additions such as -A, -O and -r are Linux-only; for a portable count, pipe to wc -l.

Options worth knowing

A selection, described in our own words. For the full list, see pgrep(1) or pgrep --help.

OptionWhat it does
-a, --list-fullPrint the full command line after each PID.
-l, --list-namePrint the process name after each PID.
-c, --countPrint the number of matches instead of PIDs.
-d, --delimiter STRINGSeparate PIDs with STRING instead of a newline.
-f, --fullMatch the pattern against the full command line, not just the name.
-x, --exactRequire the pattern to match the whole name (or command line with -f).
-i, --ignore-caseMatch case-insensitively.
-v, --inverseSelect the processes that do not match.
-n, --newestSelect only the most recently started match.
-o, --oldestSelect only the least recently started match.
-O, --older SECSSelect only processes running longer than SECS seconds.
-u, --euid USERSMatch only processes with these effective users (names or IDs).
-U, --uid USERSMatch only processes with these real user IDs.
-G, --group GIDSMatch only processes with these real group IDs.
-P, --parent PPIDSMatch only children of these parent PIDs.
-g, --pgroup PGIDSMatch only processes in these process groups.
-s, --session SIDSMatch only processes in these sessions.
-t, --terminal TTYSMatch only processes on these terminals.
-F, --pidfile FILERead the PIDs to consider from FILE.
-r, --runstates STATESMatch only processes in these states (S, R, D, Z, ...).
-A, --ignore-ancestorsExclude pgrep's own ancestors (its shell) from the matches.
-w, --lightweightList thread IDs instead of process IDs.

Related