'ps' and 'grep'


When faced with the task of finding something in "ps", old Unix hands will almost automatically type "ps -e | grep" and follow that with whatever they are looking for. I can tell you that after so many years of doing that, it's almost reflexive. We may know that there are other ways, but it's the old saying: walk too close to a habit and it will bite you.

The good thing is that most of the time that habit just wags its tail and gives us what we want. Even when there is a playful little snap of the teeth accompanying the tail wagging, we're often doing that at the command line and can ignore any superfluous output. It's when our grepping is buried in a script that the results may turn tragic.

There are a LOT of things that can go wrong with "ps -e | grep". I'll try to cover the most damaging things, but I might miss one or two. If you take away nothing else from what follows, make it this: test scripts carefully and do not assume anything!

Some alternates

There are other ways to get processes matching some string. For example, on Linux:

# ps -C watcher
  PID TTY          TIME CMD
 9153 ?        00:00:00 watcher
# ps -C sshd 
  PID TTY          TIME CMD
 2246 ?        00:00:01 sshd
 5435 ?        00:00:00 sshd
 5577 ?        00:00:00 sshd
# pgrep -l sshd
2246 sshd
5435 sshd
5577 sshd

But "-C" is different on Mac OS X:

 ps -C sshd
ps: illegal argument: sshd
usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]]
          [-g grp[,grp...]] [-u [uid,uid...]]
          [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]
       ps [-L]

OS X ps has a -C flag, but it isn't for showing processes. The "pgrep" will work, though.

OS X has another little gotcha.

$ ps -e |grep taskgated
 1403 ??         0:00.01 /usr/libexec/taskgated -s
 1432 ttys001    0:00.00 grep taskgated

Most non-BSD Unix folk would have expected one line, not two. To get that from OS X, add -c:

$ ps -ec |grep taskgated
 1403 ??         0:00.01 taskgated

There are other ways to get rid of unwanted lines. Section 3.10 of Unix - Frequently Asked Questions suggests

 ps ux | awk '/name/ && !/awk/ {print $2}'

and you might see this:

ps aux | grep something | grep -v grep

This is a clever way (though harder to type):

ps aux | grep [s]shd

In case you don't see why it's because the "grep" line will contain "grep [s]shd" (with the brackets) which won't match what grep is looking for.

But in all cases, watch your switches. On Linux, for example:

# ps a
 2833 hvc0     Ss+    0:00 /sbin/getty -8 38400 hvc0
 3257 pts/1    Ss     0:00 /bin/bash
 3271 pts/1    S      0:00 sudo su -
 3274 pts/1    S      0:00 su -
 3275 pts/1    S      0:03 -su
 5578 pts/0    Ss     0:00 -bash
 5584 pts/0    S+     0:00 screen -D -r
12201 pts/1    R+     0:00 ps a
# ps -a
  PID TTY          TIME CMD
 3271 pts/1    00:00:00 sudo
 3274 pts/1    00:00:00 su
 3275 pts/1    00:00:03 bash
 5584 pts/0    00:00:00 screen
12202 pts/1    00:00:00 ps

Those would be identical on OS X!

Before we get too deep into ps idiosyncrasies here, you may want to take a look at I_WANT_A_BROKEN_PS and How "ps" works and why.

Let's move on to look at a scripting problem:

X=`ps -e | grep $1`
# -ec on Mac
echo $X

Nothing wrong with that, right? Look, it works:

$ ./t.sh vim
1474 ttys001 0:00.00 /bin/bash ./t.sh vim 1475 ttys001 0:00.00 /bin/bash
./t.sh vim 1477 ttys001 0:00.00 grep vim 1462 ttys002 0:00.01 vim foops

OK, what about this?

$ ./t.sh taskgated
1480 aa ab bh dl ds dt ex me pj pt re sc t1 t2 tp tt xt zz 0:00.01 taskgated

What's all that "aa ab bh" stuff? Here, let's see if this helps:

$ ls ??
aa	bh	ds	ex	pj	re	t1	tp	xt
ab	dl	dt	me	pt	sc	t2	tt	zz

You have to be careful with pulling in the output of "ps" and randomly echoing it. The "ps" lines for daemons will include a "?" in the controlling tty column, so if you did "x=`ps -e | grep whatever`", the returning line would have a "?" (on Mac OS X, two "??"). If your script then does "echo $x", the ? mark or marks will match one or two character file names that happen to be present in your current directory. As this is directory dependent, your script might appear to work correctly initially and then break later.

You can get unexpected results with "pgrep" too.

Another thing that can bite you is the width of the listing. What you see with "ps" at command line is not necessarily what "grep" sees.

$ ps -e
# partial output
 1589 ??         0:00.01 /System/Library/Frameworks/CFNetwork.framework/Version
 1629 ??         0:00.23 /System/Library/CoreServices/System Events.app/Content
 1644 ??         0:00.39 /System/Library/Frameworks/CoreServices.framework/Fram
$ ps -e | grep .
 1589 ??         0:00.01 /System/Library/Frameworks/CFNetwork.framework/Versions/A/Support/cookied
 1629 ??         0:00.23 /System/Library/CoreServices/System Events.app/Contents/MacOS/System Events -psn_0_1069317
 1644 ??         0:00.48 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/
  Versions/A/Support/mdworker -s mdworker -c MDSImporterWorker -m com.apple.mdworker.shared

Without more instructions, "ps -e" stops at your terminal width. When it is piped, it does not. That could lead to more matches than you expected.

Got something to add? Send me email.

(OLDER) <- More Stuff -> (NEWER)    (NEWEST)   

Printer Friendly Version

-> -> Selecting processes from ps with grep

Increase ad revenue 50-250% with Ezoic

More Articles by

Find me on Google+

© Anthony Lawrence

Kerio Samepage

Have you tried Searching this site?

Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more.

Contact us