Right, so you’ve got a process running. You can hear its digital heartbeat, sucking up CPU cycles and memory, but you have no idea what its Process ID (PID) is. You could run ps aux | grep and start squinting at a wall of text, hoping you spot the right one. But let’s be honest, that’s what our ancestors did. We have better tools. Enter pgrep and pidof—two commands that exist for the singular, beautiful purpose of turning a process name into its PID, saving you from that grep-induced eyestrain.

The key thing to remember here is that these tools don’t find processes; they query the /proc filesystem, just like ps does. They’re essentially specialized, streamlined versions of the ps | grep pattern, designed to do one job perfectly.

pgrep: The Precision Scalpel

pgrep is the more powerful and flexible of the two. It’s basically grep for the process table, and it returns just the PIDs, which makes it perfect for scripting. Its default behavior is straightforward:

$ pgrep nginx
882
883
884
885

Boom. There are the PIDs for all processes with “nginx” in their name. But here’s the first “gotcha”: pgrep matches on the process name, not the full command line. The process name is typically just the first 15 characters of the executable name. This is a common point of confusion. If you need to match on the full command line arguments, you need the -f flag.

# This finds processes named 'python'
$ pgrep python
1234

# This finds processes whose full command line includes 'my-script.py'
$ pgrep -f my-script.py
1234

See the difference? The first one found a Python interpreter. The second one found the specific script running inside an interpreter. This distinction is everything.

pgrep also has a bunch of other useful flags. Want to see the process name next to the PID? Use -l (for “long”). Need to get the PID for the most recent process started with that name? That’s -n. The oldest? -o.

$ pgrep -l nginx
882 nginx
883 nginx
884 nginx
885 nginx
$ pgrep -n nginx
885

pidof: The Simple Sledgehammer

Now, pidof is simpler. Its entire raison d’être is to return the PIDs of all processes executing with the given name. It’s less nuanced than pgrep.

$ pidof nginx
885 884 883 882

Notice the output? It’s all on one line, space-separated. This format is brilliantly useful if you want to, say, kill all those processes with kill $(pidof nginx). It’s concise and made for command substitution.

However, pidof has a quirk, and it’s a doozy. By default, pidof ignores zombie processes. This is often sensible, but sometimes it’s not what you want. If you need to see every instance, including the undead ones, you have to use the -z flag. I don’t know why the designers chose to make the default behavior hide information, but there you go.

# Probably shows nothing if nginx is a zombie
$ pidof nginx

# Forces it to show zombie PIDs too
$ pidof -z nginx

Best Practices and Pitfalls

  1. The Zombie Problem: As mentioned, remember that pidof ignores zombies. If your process is stuck in a zombie state, pidof might pretend it doesn’t exist. pgrep doesn’t suffer from this particular madness.

  2. Signal to Noise Ratio: The most common mistake is getting too many PIDs back. You run pgrep python and get six of them. Which one is yours? This is where pgrep’s flags earn their keep. Combine -f to match the full command line and other options like -u to match a specific user.

    # Find *my* Python script, not the system's
    $ pgrep -f -u $USER my-data-processor.py
    5678
    
  3. Scripting Safety: Never do kill $(pgrep something) without thinking. What if pgrep returns nothing? Your kill command will throw an error. What if it returns multiple PIDs? You’ll kill them all. This is often what you want, but be absolutely certain it is. For a more surgical approach, use pgrep’s --exact (-x) flag to match the process name perfectly, not just a substring.

    # Kills everything with 'server' in the name. Risky.
    $ kill $(pgrep server)
    
    # Only kills processes exactly named 'my-server'
    $ kill $(pgrep -x my-server)
    
  4. The /proc Reality: Both tools are just reading the abstracted interface of /proc. They’re not magic. If a process is actively being created or destroyed the instant you run the command, you might get inconsistent results. It’s a snapshot, not a live video feed.

So, which one should you use? Use pidof for quick, simple lookups when you know the exact name and want to pipe the result directly into another command. For everything else—any time you need precision, filtering, or more information—reach for pgrep. It’s the brilliant friend that actually knows this stuff.