理解Perl单线程

时间:2015-04-21 12:31:57

标签: perl command-line process aix

我正在寻找一种检查AIX上进程内存使用情况的方法,并找到了this page,列出了这个命令:

# svmon -Pt15 | perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'

它适用于我的目的,但我想了解Perl单线部分是如何工作的。

我知道它正在解析svmon命令的输出。我已经理解了输出第二行的$.==2部分。部件$.=0会重置行号,以便它可以对svmon列出的每个流程执行相同的处理。

但是,我无法理解||$&&&!$s++部分。有OR。 $&是匹配的部分(什么?)和&amp;&amp;是AND运算符,但我不确定我是否正确分解它。

svmon返回(没有任何重定向)每个进程的类似行块。第一行类似于:

# svmon -Pt15 | head -n 20

-------------------------------------------------------------------------------
     Pid Command          Inuse      Pin     Pgsp  Virtual 64-bit Mthrd  16MB
12058652 java            579432     8261   397386   824106      Y     Y     N

     PageSize                Inuse        Pin       Pgsp    Virtual
     s    4 KB               67560        309       1610      40138
     m   64 KB               31992        497      24736      48998

    Vsid      Esid Type Description              PSize  Inuse   Pin Pgsp Virtual
  c86b4c        7e work text data BSS heap           m   4096     0   43    4096
  c30d43        7f work text data BSS heap           m   4096     0  215    4096
  db2358        68 work text data BSS heap           m   4089     0 3667    4096
  d25056        69 work text data BSS heap           m   4057     0  585    4096
  99d59b      1002 work text data BSS heap           m   3461     0 2061    4082
  b531b1        7d work text data BSS heap           m   3440     0   39    3440
  a551a7      1001 work text data BSS heap           m   2933     0 2597    3767
  970017  90000000 work shared library text          m   2172     0  213    2413
  ca3c48        6a work text data BSS heap           m   2090     0 2006    4096
  ade32e         4 work text or shared-lib code seg sm  25389     0    0   25389
... (tons of lines)
-------------------------------------------------------------------------------
     Pid Command          Inuse      Pin     Pgsp  Virtual 64-bit Mthrd  16MB
 6094910 java            494585     8110     5754   484444      Y     Y     N

     PageSize                Inuse        Pin       Pgsp    Virtual
     s    4 KB               31257        158       1610      16780
     m   64 KB               28958        497        259      29229

    Vsid      Esid Type Description              PSize  Inuse   Pin Pgsp Virtual
  a31ba7         8 work text or shared-lib code seg  m   4096     0    0    4096
  da3159         6 work text or shared-lib code seg  m   4096     0    0    4096
... repeated several times

带有perl部分的已处理输出返回标题,虚线和每个进程一行,以及命令和内存详细信息:

# svmon -Pt15 | perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'
-------------------------------------------------------------------------------
     Pid Command          Inuse      Pin     Pgsp  Virtual 64-bit Mthrd  16MB
12058652 java            579438     8261   397386   824106      Y     Y     N
 6094910 java            494583     8110     5754   484444      Y     Y     N
 5046378 java            382458     8217     5738   339847      Y     Y     N
21102818 java            352534     8149     5738   305644      Y     Y     N
18219048 java            321394     8081   176586   340617      Y     Y     N
18612404 java            235323     8161   100746   267565      Y     Y     N
 3735554 java            195412     8118   125306   222885      Y     Y     N
24772644 java            185403     8209    88474   202652      Y     Y     N
25559102 java            143341     8095     5738   118094      Y     Y     N
11272240 java            137082     8193    82810   167151      Y     Y     N
18874550 java            131531     8129    79898   144249      Y     Y     N
 5505082 java            121320     8075    50922   136195      Y     Y     N

2 个答案:

答案 0 :(得分:5)

perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'

这看起来 - 乍一看 - 就像打算每隔一行打印一样,也是---行之后的第一行。让我们来看看这些部件。

while(<>) { ... }以逐行模式读取标准输入(或文件,如果提供参数)。在单行中执行此操作的最常见方法是使用-n-p开关。即这样:

perl -e 'while(<>) { ... }'

与此相同:

perl -ne ' ... '

print if将打印$_,其中一条读取行,如果其后的条件为真。条件if ( $. == 2 || $& && !$s++ )是一块笨重的马粪。让我们剖析它。

首先,让我们注意它由两个语句组成,与||连接,这意味着如果其中一个语句为真,则整个语句为真。其次,请注意它是短路的,这意味着如果左边的声明为真,则永远不会评估右手声明。由于计数器变量$s,这与此相关。

$.是访问的最后一个输入文件句柄上的行号的内置变量。它可以被操纵,但上帝知道为什么会这样。在这种情况下,如果行号为2,则会打印该行。

如果$.不是2,则会检查右侧语句。它也是一个链式语句,&&,意味着两者都必须为真。实际上,所有三个语句都是相互链接的:a || b && c,这使得operator precedence变得相当混乱。幸运的是(?),它似乎意味着我们认为它意味着:(a || (b && c))。因此,如果$&为真,并且!$s++为真,那么打印就会通过。变量右侧的increment operator在递增之前返回值,在这种情况下,它在第一次运行代码时返回0,否则变为{ {1}},一个真正的价值。之后的所有时间,1都返回false。这是一个常见的Perl习惯用法,仅对第一个遇到的值返回true。

唷!

如果有一行只包含短划线!$s++,那么之后的部分会将$.重置为0。据推测,这是为了分离&#34;记录&#34;,例如:

----

但这引出了为什么foo bar ------ next ... 的问题?我们是否总是打印每条记录的第二行?我们总是打印第一行是#34;而不是第2行&#34;,前面是一行&#34;只是&#34;破折号!$s++

所以让我们试试并总结......这将打印

  • 输入中的第2行,只有短划线----之后的第2行,如果之间没有任何短划线
  • 第一行仅发现破折号后的第一行(只有第一行)
  

可以用更简单,更健壮的方式完成相同的结果吗?

哦,是的,当然。这是一个做同样事情的例子,但是使用更简单的工具:

----

这基本上就像英语一样,总是很好。它需要前三行并打印它们,然后检查&#34;虚线&#34;,丢弃后面的行,然后打印下一行。我使用连接运算符$ perl -ne'if ($. <= 3) { print } elsif (/^-+$/) { <>; print <>.""; }' ------------------------------------------------------------------------------- Pid Command Inuse Pin Pgsp Virtual 64-bit Mthrd 16MB 12058652 java 579432 8261 397386 824106 Y Y N 6094910 java 494585 8110 5754 484444 Y Y N 99058652 java 579432 8261 397386 824106 Y Y N 22058652 java 579432 8261 397386 824106 Y Y N 将文件句柄放在标量上下文中,只打印一行。另一种方法是使用标量变量并打印出来。

这是最好的方法吗?嗯......这是一个简单的方法。您可以通过创建程序文件来改进它,该程序文件将运行如下:

.

将它与linux系统的便捷功能相结合,您可以使用新的命令。

该计划可能是这样的:

svmon -Pt15 | perl program.pl

答案 1 :(得分:1)

您正在正确分解它,因为我们可以使用B::Deparse进行验证:

perl -MO=Deparse,-p -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'
while (defined(($_ = <ARGV>))) {
    ((($. == 2) || ($& && (!($s++)))) and print($_));
    (/^-+$/ and ($. = 0));
}

$&包含最后一个匹配项,在这种情况下,只有一个匹配位置:/^-+$/

!$s++仅在$s++为假时,即在第一场比赛($& && !$s++)时才为真。