[英]How to define new commands or macros in awk
我喜欢定义一个新命令来包装现有的 awk 命令,例如print
。 但是,我不想使用 function:
#wrap command with function
function warn(text) { print text > "/dev/stderr" }
NR%1e6 == 0 {
warn("processed rows: "NR)
}
相反,我喜欢定义一个可以在没有括号的情况下调用的新命令:
#wrap command with new command ???
define warn rest... { print rest... > "/dev/stderr" }
NR%1e6 == 0 {
warn "processed rows: "NR
}
我可以想象的一种解决方案是使用预处理器,并可能很好地设置 awk 脚本的 shebang 以调用此预处理器,然后调用 awk。但是,我更希望有一个纯粹的 awk 解决方案。
注意:该解决方案也应该在我使用的mawk中工作,因为它比普通GNU/awk 快得多。
更新:讨论表明gawk
(GNU/awk) 可以非常快并且mawk
。
看看Mawk的源代码,我发现命令很特殊,无法在运行时添加。 从kw.c
:
keywords[] =
{
{ "print", PRINT },
{ "printf", PRINTF },
{ "do", DO },
{ "while", WHILE },
{ "for", FOR },
{ "break", BREAK },
{ "continue", CONTINUE },
{ "if", IF },
{ "else", ELSE },
{ "in", IN },
{ "delete", DELETE },
{ "split", SPLIT },
{ "match", MATCH_FUNC },
{ "BEGIN", BEGIN },
{ "END", END },
{ "exit", EXIT },
{ "next", NEXT },
{ "nextfile", NEXTFILE },
{ "return", RETURN },
{ "getline", GETLINE },
{ "sub", SUB },
{ "gsub", GSUB },
{ "function", FUNCTION },
{ (char *) 0, 0 }
};
您可以通过修补Mawk的C代码来添加新命令。
你不能在任何awk中做到这一点,你不能在没有编写awk语言解析器的情况下在awk之外做到这一点,并且你可以编写自己类似于awk的命令然后实际上不再像awk那样它的行为与该名称的任何其他命令的行为不同。
奇怪的是,你将GNU awk称为“vanilla”,因为它具有比任何其他当前可用的awk更多的有用功能,而mawk只是一个针对速度优化的简化awk,仅在极少数情况下才需要。
我创建了一个名为cppawk
的 shell 包装器脚本,它结合了 C 预处理器(来自 GCC)和 Awk。
BSD 许可,它带有手册页、回归测试和简单的安装说明。
通常,C 预处理器创建看起来像函数的宏; 但是使用某些控制流技巧,它们在 Awk 中的作用与在 C 中的作用一样多,我们可以实现语法糖的小奇迹:
function __warn(x)
{
print x
return 0
}
#define warn for (__w = 1; __w; __w = __warn(__x)) __x =
NR % 5 == 0 {
warn "processed rows: "NR
}
跑步:
$ cppawk -f warn.cwk
a
b
c
d
e
processed rows: 5
f
g
h
i
j
processed rows: 10
k
因为整个for
技巧都在一行代码中,我们可以使用__LINE__
符号使隐藏变量成为准唯一的:
function __warn(x)
{
print x
return 0
}
#define xcat(a, b, c) a ## b ## c
#define cat(a, b, c) xcat(a, b, c)
#define uq(sym) cat(__, __LINE__, sym)
#define warn for (uq(w) = 1; uq(w); uq(w) = __warn(uq(x))) uq(x) =
NR % 5 == 0 {
warn "processed rows: "NR
}
扩展是:
$ cppawk --prepro-only -f warn.cwk
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "<stdin>"
function __warn(x)
{
print x
return 0
}
NR % 5 == 0 {
for (__13w = 1; __13w; __13w = __warn(__13x)) __13x = "processed rows: "NR
}
u()
宏将13
插入到变量中,因为在第 13 行调用了warn
。
希望你喜欢。
PS,也许不要这样做,但要找到一些使用cppawk
的不那么老套的方法。
您可以使用 C99/GNUC 可变参数宏,例如:
#define warn(...) print __VA_ARGS__ >> "/dev/stderr"
NR % 5 == 0 {
warn("processed rows:", NR)
}
我们制作了一个重定向到标准错误的简陋的print
包装器。它似乎什么都没有,但你不能用 Awk function 做到这一点:如果没有将它作为一个参数 function 并传递连接所有内容的表达式的值,则不能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.