Friday, December 18, 2009

ps headers and grep

GNU ps(1) has a plethora of options.  One of the more useful features of ps is the header label which is printed at the top of the ps output, such as in the following snippet:


Listing 1.1
char $ ps
  PID TTY       TIME CMD
15705 pts/1 00:00:00 bash
16345 pts/1 00:00:00 ps


As you can see, each column has a label on the top.  In this example (Listing 1.1), the columns are labelled PID, TTY, TIME and CMD.  This is the most basic invocation of the ps command, and the output is minimal.  If you start adding options, such as doing ps aux, (where you will get you a listing of all the processes on the system using BSD style syntax) you will get quite a bit more text to sift through.  But what if you are only after a certain term, such as tty, for example in the ps aux listing? To start with, you could pipe the output of ps into grep(1), in order to list only the things you are looking for:


Listing 1.2
char $ ps aux | grep tty
root 1588 0.0 0.0 1852 444 tty4 Ss+ Dec17 0:00 /sbin/mingetty tty4
root 1592 0.0 0.0 1852 440 tty6 Ss+ Dec17 0:00 /sbin/mingetty tty6
root 1634 2.2 2.7 46812 28332 tty1 Ss+ Dec17 42:09 /usr/bin/Xorg :0 -nr -verbose -auth /var/run/gdm/auth-for-gdm-6n8EnG/database -nolisten tcp vt1
root 12845 0.0 0.0 1852 444 tty3 Ss+ Dec17 0:00 /sbin/mingetty tty3
root 12898 0.0 0.0 1852 452 tty5 Ss+ Dec17 0:00 /sbin/mingetty tty5
root 14863 0.0 0.0 1852 452 tty2 Ss+ 06:57 0:00 /sbin/mingetty tty2
kermit 16382 0.0 0.0 4192 780 pts/1 S+ 21:42 0:00 grep tty


This works, but there are a couple of things I don't like about it.  First of all, there are some instances of tty that I don't want.  Most notable is the last line, which lists the instance of grep looking for 'tty'.   We can get rid of this by doing a grep -v, which basically says 'don't match this,' where this is the term you supply.

Listing 1.3
char $ ps aux | grep tty | grep -v grep | grep -v tty1
root 1588  0.0 0.0 1852 444 tty4 Ss+ Dec17 0:00 /sbin/mingetty tty4
root 1592  0.0 0.0 1852 440 tty6 Ss+ Dec17 0:00 /sbin/mingetty tty6
root 12845 0.0 0.0 1852 444 tty3 Ss+ Dec17 0:00 /sbin/mingetty tty3
root 12898 0.0 0.0 1852 452 tty5 Ss+ Dec17 0:00 /sbin/mingetty tty5
root 14863 0.0 0.0 1852 452 tty2 Ss+ 06:57 0:00 /sbin/mingetty tty2


This looks a lot better.  Notice that I actually eliminated two entries with grep -v:

Listing 1.4
char $ ps aux | grep tty | grep -v grep | grep -v tty1

First, I got rid of the line listing grep (listing 1.4a below) as well as the long line with tty1 (listing 1.4b below).

Listing 1.4a
kermit 16382 0.0 0.0 4192 780 pts/1 S+ 21:42 0:00 grep tty


Listing 1.4B
root 1634 2.2 2.7 46812 28332 tty1 Ss+ Dec17 42:09 /usr/bin/Xorg :0 -nr -verbose -auth /var/run/gdm/auth-for-gdm-6n8EnG/database -nolisten tcp vt1



In the interest of less typing, a way to shorten this string of commands would be to use the egrep(1) program, instead of grep. egrep allows for extended regular expression  usage, and can be invoked either by egrep or grep -E.

Listing 1.5
char $ ps aux | grep tty | egrep -v 'grep|tty1'
root 1588  0.0 0.0 1852 444 tty4 Ss+ Dec17 0:00 /sbin/mingetty tty4
root 1592  0.0 0.0 1852 440 tty6 Ss+ Dec17 0:00 /sbin/mingetty tty6
root 12845 0.0 0.0 1852 444 tty3 Ss+ Dec17 0:00 /sbin/mingetty tty3
root 12898 0.0 0.0 1852 452 tty5 Ss+ Dec17 0:00 /sbin/mingetty tty5
root 14863 0.0 0.0 1852 452 tty2 Ss+ 06:57 0:00 /sbin/mingetty tty2


As you can see, the command is shorter, but the output is still the same, and looks nice.  There is one other problem though; there are eleven columns, but no label to indicate the kind of information being displayed.  The label is printed with ps aux, but the grep output doesn't print that, because I didn't ask it to do that.  I need to ask grep to display all the lines with tty and the header also. Once again I will use egrep to get what I am after:


Listing 1.6
char $ ps aux | egrep 'PID|tty' | egrep -v 'grep|tty1'
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1588  0.0 0.0 1852 444 tty4 Ss+ Dec17 0:00 /sbin/mingetty tty4
root 1592  0.0 0.0 1852 440 tty6 Ss+ Dec17 0:00 /sbin/mingetty tty6
root 12845 0.0 0.0 1852 444 tty3 Ss+ Dec17 0:00 /sbin/mingetty tty3
root 12898 0.0 0.0 1852 452 tty5 Ss+ Dec17 0:00 /sbin/mingetty tty5
root 14863 0.0 0.0 1852 452 tty2 Ss+ 06:57 0:00 /sbin/mingetty tty2


I told egrep to look for both 'PID' ('PID' is found in the header label, so grep finds it and prints the entire line) and 'tty,' but not to print any line with 'tty1' or 'grep' in it.

Final thoughts:

By chaining a couple of commands together with pipes, you can produce some pretty informative, and easy to read output.  I would encourage you to read through your local man pages for ps and grep, to get a better handle on what options are available to you on your system. 

The idea of using egrep to grab the ps header is not mine.  I came across it in Æleen Frisch's book Essential System Administration, Second edition, pg 261.  This edition of her book is now out of print, however the third edition is still available.  I haven't read it (yet), but it is on my short list of books to buy.  Ironically, I picked up my copy of the second edition in a clearance bin at a local store a number of years ago.  I let it sit on my shelf for a long time after that.  Then one day I decided to start reading it, and could not put it down.  I still refer to it fairly regularly.  It is a very good book, and I would recommend it to anyone who wishes to become better at doing sys-admin type work.

No comments:

Post a Comment