📄 ch01_19.htm
字号:
<HTML><HEAD><TITLE>Recipe 1.18. Program: psgrep (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:29:27Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch01_01.htm"TITLE="1. Strings"><LINKREL="prev"HREF="ch01_18.htm"TITLE="1.17. Program: fixstyle"><LINKREL="next"HREF="ch02_01.htm"TITLE="2. Numbers"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch01_18.htm"TITLE="1.17. Program: fixstyle"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 1.17. Program: fixstyle"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch01_01.htm"TITLE="1. Strings"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="chapter"HREF="ch02_01.htm"TITLE="2. Numbers"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 2. Numbers"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch01-13481">1.18. Program: psgrep</A></H2><PCLASS="para"><ACLASS="indexterm"NAME="ch01-idx-1000010352-0"></A><ACLASS="indexterm"NAME="ch01-idx-1000010352-1"></A>Many programs, including <EMCLASS="emphasis">ps</EM>, <EMCLASS="emphasis">netstat</EM>, <EMCLASS="emphasis">lsof</EM>, <EMCLASS="emphasis">ls -l</EM>, <EMCLASS="emphasis">find -ls</EM>, and <EMCLASS="emphasis">tcpdump</EM>, can produce more output than can be conveniently summarized. Logfiles also often grow too long to be easily viewed. You could send these through a filter like <EMCLASS="emphasis">grep</EM> to pick out only certain lines, but regular expressions and complex logic don't mix well; just look at the hoops we jump through in <ACLASS="xref"HREF="ch06_18.htm"TITLE="Expressing AND, OR, and NOT in a Single Pattern">Recipe 6.17</A>.</P><PCLASS="para">What we'd really like is to make full queries on the program output or logfile. For example, to ask <EMCLASS="emphasis">ps</EM> something like, "Show me all the processes that exceed 10K in size but which aren't running as the superuser." Or, "Which commands are running on pseudo-ttys?"</P><PCLASS="para">The <EMCLASS="emphasis">psgrep</EM> program does this - and infinitely more - because the specified selection criteria are not mere regular expressions; they're full Perl code. Each criterion is applied in turn to every line of output. Only lines matching all arguments are output. The following is a list of things to find and how to find them.</P><PCLASS="para">Lines containing "sh" at the end of a word:</P><PRECLASS="programlisting">% psgrep '/sh\b/'</PRE><PCLASS="para">Processes whose command names end in "sh":</P><PRECLASS="programlisting">% psgrep 'command =~ /sh$/'</PRE><PCLASS="para">Processes running with a user ID below 10:</P><PRECLASS="programlisting">% psgrep 'uid < 10'</PRE><PCLASS="para">Login shells with active ttys:</P><PRECLASS="programlisting">% psgrep 'command =~ /^-/' 'tty ne "?"'</PRE><PCLASS="para">Processes running on pseudo-ttys:</P><PRECLASS="programlisting">% psgrep 'tty =~ /^[p-t]/'</PRE><PCLASS="para">Non-superuser processes running detached:</P><PRECLASS="programlisting">% psgrep 'uid && tty eq "?"'</PRE><PCLASS="para">Huge processes that aren't owned by the superuser:</P><PRECLASS="programlisting">% psgrep 'size > 10 * 2**10' 'uid != 0'</PRE><PCLASS="para">The last call to <EMCLASS="emphasis">psgrep</EM> produced the following output when run on our system. As one might expect, only <EMCLASS="emphasis">netscape</EM> and its spawn qualified.</P><PRECLASS="programlisting"><CODECLASS="userinput"><B><CODECLASS="replaceable"><I> FLAGS UID PID PPID PRI NI SIZE RSS WCHAN STA TTY TIME COMMAND</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I> 0 101 9751 1 0 0 14932 9652 do_select S p1 0:25 netscape</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>100000 101 9752 9751 0 0 10636 812 do_select S p1 0:00 (dns helper)</I></CODE></B></CODE></PRE><PCLASS="para"><ACLASS="xref"HREF="ch01_19.htm#ch01-28926"TITLE="psgrep">Example 1.6</A> shows the <EMCLASS="emphasis">psgrep</EM> program.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch01-28926">Example 1.6: psgrep</A></H4><PRECLASS="programlisting">#!/usr/bin/perl -w# psgrep - print selected lines of ps output by# compiling user queries into codeuse strict;# each field from the PS headermy @fieldnames = qw(FLAGS UID PID PPID PRI NICE SIZE RSS WCHAN STAT TTY TIME COMMAND);# determine the unpack format needed (hard-coded for Linux ps)my $fmt = cut2fmt(8, 14, 20, 26, 30, 34, 41, 47, 59, 63, 67, 72);my %fields; # where the data will storedie <<Thanatos unless @ARGV;usage: $0 criterion ... Each criterion is a Perl expression involving: @fieldnames All criteria must be met for a line to be printed.Thanatos# Create function aliases for uid, size, UID, SIZE, etc.# Empty parens on <ACLASS="indexterm"NAME="ch01-idx-1000011517-0"></A><ACLASS="indexterm"NAME="ch01-idx-1000011517-1"></A>closure args needed for void prototyping.for my $name (@fieldnames) { no strict 'refs'; *$name = *{lc $name} = sub () { $fields{$name} };}my $code = "sub is_desirable { " . join(" and ", @ARGV) . " } ";unless (eval $code.1) { die "Error in code: $@\n\t$code\n";}open(PS, "ps wwaxl |") || die "cannot fork: $!";print scalar <PS>; # emit header linewhile (<PS>) { @fields{@fieldnames} = trim(unpack($fmt, $_)); print if is_desirable(); # line matches their criteria}close(PS) || die "ps failed!";# convert cut positions to unpack formatsub cut2fmt { my(@positions) = @_; my $template = ''; my $lastpos = 1; for my $place (@positions) { $template .= "A" . ($place - $lastpos) . " "; $lastpos = $place; } $template .= "A*"; return $template;}sub trim { my @strings = @_; for (@strings) { s/^\s+//; s/\s+$//; } return wantarray ? @strings : $strings[0];}# the following was used to determine column cut points.# sample input data follows#123456789012345678901234567890123456789012345678901234567890123456789012345# 1 2 3 4 5 6 7# Positioning:# 8 14 20 26 30 34 41 47 59 63 67 72# | | | | | | | | | | | |__END__<CODECLASS="userinput"><B><CODECLASS="replaceable"><I> FLAGS UID PID PPID PRI NI SIZE RSS WCHAN STA TTY TIME COMMAND</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I> 100 0 1 0 0 0 760 432 do_select S ? 0:02 init</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I> 140 0 187 1 0 0 784 452 do_select S ? 0:02 syslogd</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>100100 101 428 1 0 0 1436 944 do_exit S 1 0:00 /bin/login</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>100140 99 30217 402 0 0 1552 1008 posix_lock_ S ? 0:00 httpd</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I> 0 101 593 428 0 0 1780 1260 copy_thread S 1 0:00 -tcsh</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>100000 101 30639 9562 17 0 924 496 R p1 0:00 ps axl</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I> 0 101 25145 9563 0 0 2964 2360 idetape_rea S p2 0:06 trn</I></CODE></B></CODE><CODECLASS="userinput"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -