Skip to content
Latchkey

pkill and pgrep: Match Processes by Name in CI

pgrep lists PIDs matching a name or pattern and pkill sends them a signal, so you can clean up by command name instead of hunting for PIDs.

Between CI steps you often need to stop "that node server" without knowing its PID. pgrep finds it and pkill stops it, with -f to match the full command line.

What it does

pgrep prints PIDs whose process name matches a pattern; pkill sends them a signal (SIGTERM by default). By default they match only the process name (first 15 chars of comm); -f matches against the entire command line, which is what you usually want for scripts and node/python processes.

Common usage

Terminal
pgrep -fl "test-server"          # list matching PIDs + cmdline
pkill -f "test-server"           # SIGTERM everything matching
pkill -TERM -f "node .*app.js"   # graceful, full-cmdline match
pkill -9 -u "$USER" -f vitest    # force, scoped to current user

Options

FlagWhat it does
-fMatch against the full command line, not just the name
-lpgrep: also print the process name
-u <user>Restrict to a user’s processes
-xExact match of the whole name
-<SIG>pkill: which signal to send (default TERM)
-cpgrep: print the count of matches

In CI

Prefer pgrep -fl <pattern> to preview matches before pkill, because a loose pattern can match the grep/CI process itself and kill the job. Scope with -u "$USER" on shared runners so you do not signal another tenant’s processes. pkill returns exit 1 when nothing matched, which is not an error in cleanup.

Common errors in CI

pkill exiting 1 in a cleanup step is normal: it means "no process matched", so guard with pkill ... || true. An over-broad pattern like pkill -f node can take down unrelated tooling; make patterns specific. Without -f, a pattern matching arguments rather than the binary name silently matches nothing.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →