今天我在网上搜索一个命令来打印模式后的下两行,我遇到了一个我无法理解的 awk 命令。
$ /usr/xpg4/bin/awk '_&&_--;/PATTERN/{_=2}' input
有人可以解释一下吗?
有关此处重复的答案,请参阅https://stackoverflow.com/a/17914105/1745001 。
_
在这里被用作变量名(有效但显然令人困惑)。如果将其重写为:
awk 'x && x--; /PATTERN/ { x=2 }' input
那么解析起来会容易一些。每当/PATTERN/
匹配时,变量就会被设置为2
(并且该行不输出) - 这是后半部分。第一部分在x
不为零时触发,并减少x
并打印当前行(默认操作,因为该子句未指定操作)。
最终结果是在模式的任何匹配之后立即打印两行,只要这两行都不匹配模式。
简单地说,该命令在给定的正则表达式匹配后打印多行,不包括匹配的行。
行数在块中指定,如果行匹配{_=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
它完全被破坏了,应该不惜一切代价避免。
解释
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 将打印这些行。
然而,很好的谜题;)
奇妙的晦涩。时间允许时会更新。
_
被用作变量名。&&
是一个逻辑运算符,它有 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