Dave Taylor answers free tech support questions about a wide variety of business and technical topics, including blogging, iphone help, ipod help, AdSense, MySpace, Sony PSP help, Mp3 players, Windows XP, Windows Vista, Linux, SEO, Mac OS X, Facebook, Twitter and LinkedIn.

Extracting the correct column with "ps" and "awk"

A reader writes:
Every *nix implementation is different. But I'm seeing some some shared behavior between HPUX and Solaris with script #52 Killing Processes by Name. The problem is that the script is trying to kill the "tty" name, instead of the pid.

Wish I understood the following line better so I could make it grab the right columns. :-\

pids=$(ps cu -U $user | awk "/ $1$/ { print \$2 }")


Dave's Answer: Let's tackle this backwards, shall we?

The last line assigns the result of the shell escaped ps | awk pipe to a shell variable called "pids" (this is indicated by the $( and ) pair).

Within the shell, the ps command lists all processes, with the two flags 'c' and 'u', which change the command name to be just the executable name, and display useful information too, and the '-U user' flag limits results to just the specified user (in case more than one user has processes running on the tty device).

The output is expected to look like this:

$ ps -cu -U taylor
USER     PID %CPU %MEM      VSZ    RSS  TT  STAT STARTED      TIME COMMAND
taylor   222   4.3 -3.9   329032  81652  ??  Ss   Thu08PM 108:00.19 WindowServer
taylor  1760   3.3 -0.4   202792   8792  ??  R    10:09AM   0:09.09 Terminal
taylor  1162   1.0 -1.2   269288  25800  ??  S    Sat08AM  29:42.57 iChat
taylor   714   0.4 -1.3   242220  27564  ??  S    Fri08AM  23:57.56 iTunes
taylor   287   0.0 -0.6   208284  13468  ??  S    Thu08PM   1:53.66 Dock
(this is a subset of the output)

Now you can see that if we search for a specific pattern, we'll match all lines that are associated with a specific process name. This could be done with grep, but using awk is useful because we can then control which of the output fields is listed too (we only want the PID, field #2). That's what the second part of the pipe does.

The problem you're seeing is that your version of Unix isn't returning the same results for the ps -cu -Uuser command. That being the case, you're probably seeing output like this:

  PID  TTY       TIME COMMAND
 10361 ttyrb     0:00 sleep
In which case you'll want to change the second part of the awk statement to extract the first field not the second (since the PID is in field one now). It would look like this:
pids=$(ps cu -U $user | awk "/ $1$/ { print \$1 }")
Try that and see if you have better results!


Help others find this article at Del.icio.us, Digg, Netscape, Reddit, and Simpy.


Subscribe!

Never miss another useful Q&A article again! Subscribe to AskDaveTaylor with Google Reader.

Comments

check the output of "who". Now how will you kill all the processes by specific IP Address of a specific user.

Posted by: linuxbug at December 22, 2005 7:36 AM

An interesting question. Sounds like you need two 'grep' commands in a row. Here's what "who" looks like:

$ who
dtint ttyp2 Dec 20 01:23 (71.138.150.180)
dtint ttyp3 Dec 22 14:44 (67.165.197.92)

So the first step would be to map the IP address to the tty device. Let's say I was interested in the first login... so I could do something like this:

tty="$(who | grep 71.138.150.180 | head -1 | awk '{print $2}')"

now I have in the 'tty' variable the device name. The next step is to simply feed that to the ps command, utilizing the "-t" flag. Well, not quite, because 'who' returns 'ttyp2", but we actually want "p2" for the "ps" command, so we'd need a slight tweak:

tty="$(echo $tty | sed 's/tty//')"

now we're ready:

ps -t $tty

The rest I'll leave as an exercise to the reader.:-)

Posted by: Dave Taylor at December 22, 2005 7:48 AM

I have a file that looks like

161 16385 11_15
161 16388 11_15
161 16393 11_15
161 16399 11_15
159 94306 3_13
159 94308 3_13
159 94310 3_13

How do I extract first two columns based on the third column (all columns with 11_15), so forth?

Posted by: TJAIN at February 13, 2007 8:54 AM

That should be easy. Something like this

for matchingline in $(grep "11_15" inputfile)
do
field1=$(echo $matchingline | cut -f1)
done

etc.

Posted by: Dave Taylor at February 13, 2007 9:20 AM

I have a lot to say, but ...
Starbucks coffee cup I have a lot to say, and questions of my own for that matter, but most of all I'd like to say thank you for all your efforts on this Web site by buying you a chai!

I do have a comment, now that you mention it!









Remember personal info?


Please note that I will never send you any unsolicited commercial email. Ever.

While I'm at it, please note that by submitting a question or comment you're agreeing to my terms of service, which are: you relinquish any subsequent rights of ownership to your material by submitting it on this site.









Uniblue: Free Virus Scan


Join Me At:
Aloha Social Media Summit, Oct 2008


Search
Find just the answers you seek from among our 1700+ free tech support articles by using our Lijit search engine.


Help!





Subscribe to
Ask Dave Taylor!

Add to Google Reader
Add to My Yahoo!
Subscribe in NewsGator Online

RDF   XML

Free Updates!
Sign up and get free weekly updates and special offers on books, seminars, workshops and more.


Recent Entries
Join the List!
Join my author info mailing list, where you'll learn about my upcoming books, speaking gigs, and more!


Book Links
© 2002 - 2008 by Dave Taylor. All Rights Reserved.

Note: This web site is for the purpose of disseminating information for educational purposes, free of charge, for the benefit of all visitors. We take great care to provide quality information. However, we do not guarantee, and accept no legal liability whatsoever arising from or connected to, the accuracy, reliability, currency or completeness of any material contained on this web site or on any linked site.

[whiteboard marker tray]