今天我在网上搜索一个命令来打印模式后的下两行,我遇到了一个我无法理解的 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