了解 Perl one-liner
Understanding a Perl one-liner
我正在寻找一种方法来检查 AIX 上进程的内存使用情况并找到 this page,列出此命令:
# svmon -Pt15 | perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'
它对我来说工作得很好,但我想了解 Perl one-liner 部分是如何工作的。
我知道它正在解析 svmon
命令的输出。我已经理解了输出第二行的 $.==2
部分。 $.=0
部分重置了行号,因此它可以对 svmon
.
列出的每个进程执行相同的处理
然而,我对||$&&&!$s++
部分感到茫然。有一个或。 $&
是匹配的部分(什么?),&& 是 AND 运算符,但我也不确定我是否正确分解了它。
svmon
returns(没有任何重定向)每个进程类似的行块。第一行类似于:
# 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 部分的处理输出 returns headers,虚线和每个进程一行,以及命令和内存详细信息:
# 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
您正在正确分解它,我们可以用 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++
).
perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'
乍一看,这看起来像是每隔一行打印一次,也是 ---
行之后的第一行。让我们看看零件。
while(<>) { ... }
以逐行模式读取标准输入(或文件,如果您提供参数)。在单行中执行此操作的最常见方法是使用 -n
或 -p
开关。 IE。这个:
perl -e 'while(<>) { ... }'
与此相同:
perl -ne ' ... '
如果后面的条件为真,print if
将打印 $_
,其中一个读取行。条件if ( $. == 2 || $& && !$s++ )
是一块笨重的马粪。让我们剖析它。
首先,让我们注意它由两个语句组成,用 ||
连接,这意味着如果其中一个语句为真,则整个语句为真。其次,请注意它是短路的,这意味着如果左边的语句为真,则永远不会评估右边的语句。这是相关的,因为计数器变量 $s
.
$.
是最后访问的输入文件句柄上行号的内置变量。它可以被操纵,但天知道人们为什么想要这样做。在这种情况下,如果行号为 2
,则打印该行。
如果$.
不是2
,检查右边的语句。它也是一个链式语句,带有 &&
,意味着两者都必须为真。实际上,所有三个语句都相互链接:a || b && c
,这使得变量 return 和值 右侧的 operator precedence. Luckily (?), it seems to mean what we assume it means: (a || (b && c))
. So, if $&
is true, and !$s++
is true, the print goes through. The increment operator 变得相当复杂在 递增之前,在这种情况下,它 returns 0
第一次代码是 运行,取反变成 1
,一个真值。此后的所有时间里,!$s++
return 都是假的。这是一个常见的 Perl 习语 return 仅对第一个遇到的值为真。
呸!
如果有一行仅由破折号 ----
组成,则之后的部分会将 $.
重置为 0
。大概这样做是为了分隔"records",例如:
foo
bar
------
next
...
但这引出了一个问题,为什么要 !$s++
?我们总是打印每条记录的第二行吗?我们总是打印第一行 "not line #2",前面是一行 "just" 破折号 ----
。
所以让我们尝试总结一下...这将打印
- 行号2在输入中,or第2行后一行只有破折号
----
,if有中间没有只有破折号的线条。
- 它找到的第一行破折号之后的第一行(而且只有第一条破折号)
Can the same result be done in a simpler, more robust way?
哦,是的,当然。这是做同样事情的例子,但使用更简单的工具:
$ 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
这基本上读起来像英文,这总是很好。它获取前三行并打印它们,然后检查 "dash line",丢弃其后的行,并打印下一行。我使用连接运算符 .
将文件句柄置于标量上下文中,以便仅打印一行。另一种方法是使用标量变量并打印它。
这是最好的方法吗?嗯...这是一个简单的方法。你可以通过创建一个程序文件来改进它,这将是 运行 比如:
svmon -Pt15 | perl program.pl
将它与 linux 系统的便利功能相结合,您将拥有一个新的命令供您使用。
那个程序可能是这样的:
use strict;
use warnings;
print <> . "" for 1 .. 3;
while (<>) {
if (/^-+$/) {
<>;
print <> . "";
}
}
我正在寻找一种方法来检查 AIX 上进程的内存使用情况并找到 this page,列出此命令:
# svmon -Pt15 | perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'
它对我来说工作得很好,但我想了解 Perl one-liner 部分是如何工作的。
我知道它正在解析 svmon
命令的输出。我已经理解了输出第二行的 $.==2
部分。 $.=0
部分重置了行号,因此它可以对 svmon
.
然而,我对||$&&&!$s++
部分感到茫然。有一个或。 $&
是匹配的部分(什么?),&& 是 AND 运算符,但我也不确定我是否正确分解了它。
svmon
returns(没有任何重定向)每个进程类似的行块。第一行类似于:
# 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 部分的处理输出 returns headers,虚线和每个进程一行,以及命令和内存详细信息:
# 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
您正在正确分解它,我们可以用 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++
).
perl -e 'while(<>){print if($.==2||$&&&!$s++);$.=0 if(/^-+$/)}'
乍一看,这看起来像是每隔一行打印一次,也是 ---
行之后的第一行。让我们看看零件。
while(<>) { ... }
以逐行模式读取标准输入(或文件,如果您提供参数)。在单行中执行此操作的最常见方法是使用 -n
或 -p
开关。 IE。这个:
perl -e 'while(<>) { ... }'
与此相同:
perl -ne ' ... '
如果后面的条件为真,print if
将打印 $_
,其中一个读取行。条件if ( $. == 2 || $& && !$s++ )
是一块笨重的马粪。让我们剖析它。
首先,让我们注意它由两个语句组成,用 ||
连接,这意味着如果其中一个语句为真,则整个语句为真。其次,请注意它是短路的,这意味着如果左边的语句为真,则永远不会评估右边的语句。这是相关的,因为计数器变量 $s
.
$.
是最后访问的输入文件句柄上行号的内置变量。它可以被操纵,但天知道人们为什么想要这样做。在这种情况下,如果行号为 2
,则打印该行。
如果$.
不是2
,检查右边的语句。它也是一个链式语句,带有 &&
,意味着两者都必须为真。实际上,所有三个语句都相互链接:a || b && c
,这使得变量 return 和值 右侧的 operator precedence. Luckily (?), it seems to mean what we assume it means: (a || (b && c))
. So, if $&
is true, and !$s++
is true, the print goes through. The increment operator 变得相当复杂在 递增之前,在这种情况下,它 returns 0
第一次代码是 运行,取反变成 1
,一个真值。此后的所有时间里,!$s++
return 都是假的。这是一个常见的 Perl 习语 return 仅对第一个遇到的值为真。
呸!
如果有一行仅由破折号 ----
组成,则之后的部分会将 $.
重置为 0
。大概这样做是为了分隔"records",例如:
foo
bar
------
next
...
但这引出了一个问题,为什么要 !$s++
?我们总是打印每条记录的第二行吗?我们总是打印第一行 "not line #2",前面是一行 "just" 破折号 ----
。
所以让我们尝试总结一下...这将打印
- 行号2在输入中,or第2行后一行只有破折号
----
,if有中间没有只有破折号的线条。 - 它找到的第一行破折号之后的第一行(而且只有第一条破折号)
Can the same result be done in a simpler, more robust way?
哦,是的,当然。这是做同样事情的例子,但使用更简单的工具:
$ 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
这基本上读起来像英文,这总是很好。它获取前三行并打印它们,然后检查 "dash line",丢弃其后的行,并打印下一行。我使用连接运算符 .
将文件句柄置于标量上下文中,以便仅打印一行。另一种方法是使用标量变量并打印它。
这是最好的方法吗?嗯...这是一个简单的方法。你可以通过创建一个程序文件来改进它,这将是 运行 比如:
svmon -Pt15 | perl program.pl
将它与 linux 系统的便利功能相结合,您将拥有一个新的命令供您使用。
那个程序可能是这样的:
use strict;
use warnings;
print <> . "" for 1 .. 3;
while (<>) {
if (/^-+$/) {
<>;
print <> . "";
}
}