Skip to content
shellmap

Find a process ID by name

Look up the PID(s) of a running process given its executable name — the lookup that precedes most kill / signal / inspect operations.

How to find a process id by name in each shell

Bashunix
pgrep -x nginx

`-x` requires EXACT match against argv[0]. Without it, `pgrep nginx` also matches `nginx-proxy`, `gunicorn` (if cmdline contains "nginx"), etc. Use `-f` to match the full command line, `-l` to print name alongside.

Zshunix
pgrep -x nginx
Fishunix
pgrep -x nginx
PowerShellwindows
(Get-Process -Name nginx -ErrorAction SilentlyContinue).Id

`-Name` matches against `ProcessName` (the .exe filename without extension). Returns multiple PIDs when multiple instances run; `-ErrorAction SilentlyContinue` avoids the "Cannot find a process" error on zero matches.

cmd.exewindows
tasklist /fi "imagename eq nginx.exe" /nh /fo csv

`/nh` strips the header row; `/fo csv` makes it parseable (PID is the second comma-separated field). Without `.exe`, the filter matches nothing — Windows always includes the extension in `imagename`.

Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.

Gotchas & notes

  • **`pgrep -x` vs `-f` is the most common source of "wrong PID" bugs**: by default `pgrep` matches `nginx` against argv[0] (the program name). With `-x` the entire argv[0] must equal the pattern (no partial). With `-f` the pattern is matched against the FULL command line (argv concatenated with spaces). For `java -jar myapp.jar`, the argv[0] is `java` — only `pgrep -f myapp` finds it; `pgrep java` returns every JVM (IDE, build, app, sbt, etc.). Anti-pattern: `pgrep myapp` for a Java/Python/Node app — you'll either miss it or match siblings.
  • **`pidof` is Linux-only (procps-ng package)** and matches only the binary basename (`pidof nginx` returns nothing for `/usr/local/bin/my-nginx-wrapper` even if it's the only one running). It's strictly less flexible than `pgrep`; the one advantage is that it returns ALL PIDs space-separated on one line (handy for `kill $(pidof nginx)`). BSD/macOS has no `pidof` — use `pgrep` (present everywhere) or `ps -o pid= -C nginx` (GNU `-C` flag — also not on BSD).
  • **pwsh `Get-Process -Name nginx` is case-INSENSITIVE on Windows, case-SENSITIVE on Linux/macOS** when running PowerShell 7. This catches scripts moving between platforms. Workaround: lowercase the filter (`Get-Process | Where-Object Name -eq "nginx"`) — `Where-Object` follows the same case rules as `-eq` (insensitive by default; use `-ceq` for case-sensitive). For the FULL command line (analogous to `pgrep -f`), pwsh requires a CIM query: `Get-CimInstance Win32_Process -Filter "CommandLine LIKE \'%myapp%\'" | Select-Object ProcessId, CommandLine` — slower than `Get-Process` but exposes the command line that `Get-Process` does NOT.
  • **Self-exclusion**: `pgrep -x bash` from a bash script returns the script's OWN PID alongside whatever else you wanted. Excluding self: `pgrep -x bash | grep -v ^$$\$` or pass `--newest`/`--oldest` to pick a single one. Same trap with `pgrep -f myscript.sh` — the running grep process and the script process both match. Use `pgrep -f myscript.sh | grep -v $$` or `pidof -o $$ myscript.sh` (`-o` excludes a PID).
  • **For "exactly one PID expected" assertions**: `pgrep -x nginx | wc -l` should be 1 — wrap in a check: `[ "$(pgrep -x nginx | wc -l)" -eq 1 ] || { echo "expected exactly 1 nginx"; exit 1; }`. pwsh: `@(Get-Process -Name nginx).Count -eq 1`. Bare `(Get-Process -Name nginx).Count` returns `$null` when no matches (no auto-unwrap to array of 0) — always coerce with `@(…)`. This single-PID check is critical for `kill -HUP $(pidof X)` patterns where killing two PIDs has different semantics than killing one (config reload vs accidental cross-traffic-restart).

Related commands

Related tasks