17

今天我在网上搜索一个命令来打印模式后的下两行,我遇到了一个我无法理解的 awk 命令。

$ /usr/xpg4/bin/awk '_&&_--;/PATTERN/{_=2}' input

有人可以解释一下吗?

4

5 回答 5

38

有关此处重复的答案,请参阅https://stackoverflow.com/a/17914105/1745001 。

于 2013-08-23T18:25:55.183 回答
15

_在这里被用作变量名(有效但显然令人困惑)。如果将其重写为:

awk 'x && x--; /PATTERN/ { x=2 }' input

那么解析起来会容易一些。每当/PATTERN/匹配时,变量就会被设置为2(并且该行不输出) - 这是后半部分。第一部分在x不为零时触发,并减少x并打印当前行(默认操作,因为该子句未指定操作)。

最终结果是在模式的任何匹配之后立即打印两行,只要这两行都不匹配模式。

于 2013-08-23T16:56:45.583 回答
8

简单地说,该命令在给定的正则表达式匹配后打印多行,不包括匹配的行。

行数在块中指定,如果行匹配{_=2},则变量_设置为 2 PATTERN。在匹配行之后读取的每一行都会导致_递减。你可以读_&&_--得好像_大于零然后减去一,这发生在匹配后的每一行,直到_达到零。当您将变量替换_为更合理的名称时,这非常简单,例如n.

一个简单的演示应该清楚(打印任何匹配行之后的 2 行foo):

$ cat file
foo
1
2
3
foo
a
b
c

$ awk 'n && n--;/foo/{n=2}' file
1
2
a
b

所以n只有当它在匹配一行后设置为 2 时才为 True,foo然后它会递减n并打印当前行。由于awk短路评估n仅在n为 True (n>0)时递减,因此在这种情况下唯一可能的值n是 2,1 或 0。

awk 具有以下结构condition{block},当条件评估为 True 时,将为当前记录执行块。如果您不提供块,则awk使用默认块{print $0},因此n && n--;没有块的条件仅n在正则表达式匹配后的行中计算为 True。分号只是为条件划定了条件n&&n--/foo/明确表示条件没有块。

要打印匹配后的两行,包括你会做的匹配:

$ awk '/foo/{n=3} n && n--' file
foo
1
2
foo
a
b

额外的额外:使用完整路径的事实/usr/xpg4/bin/awk告诉我这段代码是为 Solaris 机器设计的,因为/usr/bin/awk它完全被破坏了,应该不惜一切代价避免。

于 2013-08-23T16:56:40.767 回答
3

解释

awk表达式具有以下形式:

condition action; NEXT_EXPRESSION

如果条件为真,则将执行操作。进一步注意,如果条件为真但动作已被省略awk,将执行print(默认动作)。

您的代码中有两个表达式将在每一行输入中执行:

_&&_--          ;
/PATTERN/{_=2}

两者之间用 . 分隔;。正如我所说,print如果省略该操作,则会发生默认操作,它与以下内容相同

_&&_--    {print};
/PATTERN/ {_=2}

在您的示例_中是一个变量名称,0在第一次使用之前,它在输入的第一行被初始化 - 由 awk 自动执行。

第一个条件是(0) && (0).. 导致条件为假的结果是什么,因为0 && 0计算结果为false并且 awk 不会打印。

如果找到模式,_将设置为2使第一个条件(2) && (2)位于下一行和(1) && (1)该行之后的下一行,因为_在评估条件后递减。两者都在评估true并且 awk 将打印这些行。

然而,很好的谜题;)

于 2013-08-23T17:05:37.923 回答
2

奇妙的晦涩。时间允许时会更新。

_被用作变量名。&&是一个逻辑运算符,它有 2 个真正的动作一起运行。一旦 _ 的值减少到零,&& 的第二半为假并且不生成任何输出。

print -- "
xxxxx
yyyy
PATTERN
zzz
aa
bbb
ccc
ddd" | awk '_&&_--;/PATTERN/{_=2}'

输出

zzz
aa

调试版本

print -- "
xxxxx
yyyy
PATTERN
zzz
aa
bbb
ccc
ddd" | awk '_&&_--;{print "_="_;print _&&_};/PATTERN/{_=2;print "_="_ }'

输出

_=
0
_=
0
_=
0
_=
0
_=2
zzz
_=1
1
aa
_=0
0
_=0
0
_=0
0
_=0
0
于 2013-08-23T16:53:55.323 回答