[英]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.