2015-04-21 69 views
0

我一直在尋找一種方法來檢查進程的內存使用情況在AIX上,發現this page,列出以下命令:瞭解Perl的一個班輪

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

它工作正常,我的目的,但我想了解Perl單線程部分如何工作。

我知道它解析了svmon命令的輸出。我已經理解了輸出第二行的部分$.==2。部分$.=0重置行號,以便它可以爲svmon列出的每個進程執行相同的處理。

但是我很遺憾地理解||$&&&!$s++這個部分。有一個OR。 $&是匹配的部分(什麼?)和& &是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 
+0

這是一個必要的複雜的一行,它看起來像它可能是脆弱的。 (Ab)使用'$ .'看起來非常粗略。 – TLP

+0

可以用更簡單,更穩健的方式完成相同的結果嗎? – Snark

+0

幾乎可以肯定的是,雖然沒有定義或者輸入樣本會有些猜測。 – TLP

回答

4
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,一個真實值。所有時間後,!$s++返回false。這是一個常見的Perl成語,只有在遇到第一個值時才返回true。

唷!

之後的部分重置$.0如果有一條線只包含破折號。據推測,這是爲了單獨的「記錄」,例如:

foo 
bar 
------ 
next 
... 

但是,這引出了一個問題,爲什麼!$s++?我們是否總是打印每條記錄的第二行?我們總是打印「不是#2線」的第一行,前面是一行「正好」的破折號。

所以讓我們嘗試和總結......這行後打印

  • 行號2的輸入, 2號線僅破折號,如果沒有線只有在兩者之間破折號。
  • 第一行之後的第一行的唯一破折號發現(只有第一)

可以同樣的結果在一個更簡單,更強大的方式來完成?

哦,是的,當然。下面是做同樣的事情的一個例子,但使用更簡單的工具:

$ 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 

這基本上就像英文,這總是很好。它需要前三行,並打印它們,然後檢查「虛線」,放棄後面的行,並打印下一行。我使用連接運算符.將文件句柄置於標量上下文中,以僅打印一行。另一種方法是使用標量變量並打印該變量。

這是最好的方法嗎?呃...這是一個簡單的方法。您可以通過創建一個程序文件,它想運行改進很多:

svmon -Pt15 | perl program.pl 

與Linux系統結合起來方便的功能,您在您的處置有一個新的命令。

該方案可能是這樣的:

use strict; 
use warnings; 

print <> . "" for 1 .. 3; 

while (<>) { 
    if (/^-+$/) { 
     <>; 
     print <> . ""; 
    } 
} 
1

您是正確地分解它,因爲我們可以B::Deparse驗證:

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

$&包含了最後一場比賽,在這種情況下,只有一個地方wher e匹配發生:/^-+$/

!$s++只有當$s++爲假時,即在第一次匹配時($& && !$s++),才爲真。

+0

謝謝!但是'$ s ++'路徑呢?它增加了一些東西,但我找不到目的。 – Snark

+0

你可以將'svmon'的輸出添加到問題中嗎? – choroba

+0

perl解析它後的輸出還是原始輸出?如果是後者,這是巨大的(我的服務器上有4813行)。恐怕我無法在任何地方託管它,出於保密原因。 – Snark