簡體   English   中英

awk中如何定義新命令或宏

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM