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!
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 PID TTY STAT TIME COMMAND 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:
#!/bin/bash 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.
More Articles by Anthony Lawrence © 2013-08-16 Anthony Lawrence
I was taught that the human brain was the crowning glory of evolution so far, but I think it’s a very poor scheme for survival (Kurt Vonnegut).
Printer Friendly Version
'ps' and 'grep' Copyright © August 2013 Tony Lawrence
Have you tried Searching this site?
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
Printer Friendly Version