关于仅第一次出现的两个模式之间的匹配存在几个问题(例如,这) - 但它们似乎都依赖于exit
,这不好,因为我想继续处理该文件。
我想要做的是修改模式之间范围的第一次出现(但不是其他出现)并执行其他 awk foo.具体来说,我正在尝试注释/注释 dovecot conf 文件的某些部分。在一个真正理想的世界中,我想要一行*来确保该userdb { driver = prefetch }
块未被注释,并且所有其他userdb { }
块都被注释。但由于该文件至少是可以预测的,因此我的目标是取消注释第一个注释块,然后注释所有其他块。
我有
... some stuff that should be echoed as is ...
#userdb {
# driver = prefetch
#}
... more stuff
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
... still more stuff
#userdb {
#driver = static
#args = uid=vmail gid=vmail home=/var/vmail/%u
#}
而且我要
... original stuff ...
userdb {
driver = prefetch
}
... more stuff
#userdb {
# driver = sql
# args = /etc/dovecot/dovecot-sql.conf.ext
#}
... still more stuff
#userdb {
#driver = static
#args = uid=vmail gid=vmail home=/var/vmail/%u
#}
我以为我会在 awk 中设置一个标志来达到某个目的,因此:
awk '/^#userdb/,/^#}/ && !ididit {
print substr($0,2);
next;
ididit=1;
}
/^userdb/,/}/ {
print "#", $0;
next
}
{print}' auth-sql.conf.ext
这是非常接近的,但是设置我的ididit
标志(我添加了一堆打印,只是为了确保它确实被设置)并没有减少它:
... original stuff ...
userdb {
driver = prefetch
}
... more stuff
# userdb {
# driver = sql
# args = /etc/dovecot/dovecot-sql.conf.ext
# }
... more stuff ...
userdb {
#driver = static
#args = uid=vmail gid=vmail home=/var/vmail/%u
}
请注意,最后一个userdb {}
块设法取消了自身的注释。这非常令人烦恼,直到我发现深入肠子GNU awk 文档这个小宝石:
echo Yes | awk '/1/,/2/ || /Yes/'
这个程序的作者的本意是
(/1/,/2/) || /Yes/
。然而,awk 将其解释为/1/, (/2/ || /Yes/)
.这无法更改或解决;范围模式不与其他模式组合。
所以,我的孩子&& !ididit
是一个无用的人。
关于如何让这一切(或者更好的是我上面的“在一个真正理想的世界中”)发生在一行*上,有什么建议吗?perl
不是一个选择,但sed
甚至bash
可以是。
*“单行”可以是相当复杂的行,尽管我仍然希望它易于理解,并抛出合理的退出代码 - 我正在尝试将其放入 AWS CloudFormation 模板中。
FWIW
$awk -V
GNU Awk 4.0.2
谢谢!
答案1
似乎有一种哲学认为,您应该在 awk
脚本中的“模式”(即 之前的内容{
)中进行尽可能多的测试。早在遇到 之前,我就已经使用 C 和其他语言进行编程,因此在合适的时候awk
我并不不愿意使用一个 (或三个)语句。if
所以这就是我想出的:
awk '/userdb/,/}/ {
if (!comment) { # Uncomment the first one
sub("#", "")
print
if ($0 ~ /}/) comment=1 # All others get commented
} else {
if ($0 ~ /^[[:blank:]]*#/) { # Already commented out?
print
} else {
print "#" $0
}
}
next
}
{ print }
'
这显然是基于你的代码。
comment
是一个类似于你的变量ididit
;它最初为 0(假),并在处理第一个块后设置为 1(真)。
在一个/userdb/
-/}/
块内,
- 如果我们取消评论,
- 用于
sub
删除 a (#
如果有)。这比无条件撕掉第一个字符更安全——如果代码是已经未注释? - 当我们看到
}
(标记块的结尾)时,设置标志comment
,这样所有未来的匹配都将被注释掉。
- 用于
- 如果我们评论的话
- 如果该行已被注释,则按原样打印,
- 否则,
#
在前面加一个。
请注意,取消注释的代码假定第一个块没有包含任何意见。例如,
userdb {
driver = prefetch # We want to keep this uncommented.
}
将更改为
userdb {
driver = prefetch We want to keep this uncommented.
}
看起来这是一个错误。