是否可以在 jq 中定义自定义“@”转义函数?

Is it possible to define a custom "@" escape functions in jq?

我们有许多内置 format/escape 函数:@csv@sh

… | @sh
@sh "\( … )"

可以定义自定义 format/escape 函数,比如 @sql?

嗯。从技术上讲,是的。我不认为我可以推荐它,但它似乎是可能的。

首先,您需要了解 @csv@sh 等从 jq 的角度来看并不是独立的功能。它们都是由 format/1 函数实现的。此函数采用单个字符串参数,即要使用的格式的名称,例如"csv""sh"。你可以重新定义这个函数,你看jq会用它来格式化!

jq -n 'def format(fstring): "XXX";[1,2,3]|@json'
"XXX"

好吧,这不是很有用。这个怎么样?

jq -n '
    def format(fstring):
        if fstring=="sparkle" then
            ".:!" + (tostring) + "!:."
        else
            oldformat(fstring)
        end
    ;
    [1,2,3]|@sparkle
'
".:![1,2,3]!:."

成功了!但是不要太兴奋...

jq -n '
    def format(fstring):
        if fstring=="sparkle" then
            ".:!" + (tostring) + "!:."
        else
            oldformat(fstring)
        end
    ;
    [1,2,3]|@json
'

呃哦,那只是挂起。虽然我们希望在不知道如何处理格式时委托给原始格式,但实际上我们递归地调用了我们的新格式函数。它只是永远地调用自己。看起来我们在这个被诅咒的任务中可能运气不好。不过,如果我们仔细阅读jq手册,还是有一线希望的:

Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping.

太棒了!我们可以使用这个保存旧格式的函数:

jq -n '
    def oldformat(fstring):
        format(fstring);
    def format(fstring):
        if fstring=="sparkle" then
            ".:!" + (tostring) + "!:."
        else
            oldformat(fstring)
        end
    ;
    [1,2,3]|(@sparkle,@json,@sh)
'
".:![1,2,3]!:."
"[1,2,3]"
"1 2 3"

我真的不推荐这样做:这样做很尴尬,不是很有用,而且我不知道它是否会破坏其他东西。 format 函数似乎没有记录,因此它可能是不受支持的实现细节。但发现 在技术上 是可行的,这真是令人着迷。