jq try .. catch即使没有错误也可以直接捕获

时间:2019-11-15 14:57:48

标签: try-catch jq

因此,无需尝试抓住我的jq行,一切都会顺利进行。

我需要尝试并抓住,因为此示例有效,但不适用于所有输入:

> cat movies.json | jq '.[3]' |
  jq '.release_date |= if . == null or . == ""
                       then .
                       else (. | strptime("%Y-%m-%d") | mktime) end'
{
  "id": "166428",
  "title": "How to Train Your Dragon: The Hidden World",
  "poster": "https://image.tmdb.org/t/p/w1280/xvx4Yhf0DVH8G4LzNISpMfFBDy2.jpg",
  "overview": "As Hiccup fulfills his dream of creating a peaceful dragon utopia, Toothless’ discovery of an untamed, elusive mate draws the Night Fury away. When danger mounts at home and Hiccup’s reign as village chief is tested, both dragon and rider must make impossible decisions to save their kind.",
  "release_date": 1546473600
}

当我添加try and catch时,我得到了:

> cat movies.json | jq '.[3]' |
  jq '.release_date |= try (if . == null or . == ""
                            then .
                            else (. | strptime("%Y-%m-%d") | mktime) end)
                        catch (.)'
{
  "id": "166428",
  "title": "How to Train Your Dragon: The Hidden World",
  "poster": "https://image.tmdb.org/t/p/w1280/xvx4Yhf0DVH8G4LzNISpMfFBDy2.jpg",
  "overview": "As Hiccup fulfills his dream of creating a peaceful dragon utopia, Toothless’ discovery of an untamed, elusive mate draws the Night Fury away. When danger mounts at home and Hiccup’s reign as village chief is tested, both dragon and rider must make impossible decisions to save their kind.",
  "release_date": {
    "__jq": 0
  }
}

这是我的版本:

> jq --version
jq-1.6

最后,我想得到这样的效果:

> cat movies.json |
  jq 'map_values(try (.release_date |= if . == null or . == ""
                                       then .
                                       else (. | strptime("%Y-%m-%d") | mktime) end)
                 catch (.))'

2 个答案:

答案 0 :(得分:1)

更新::看来您发现了a bug

我对您的问题陈述的某些部分不清楚:

  • 您特殊使用null"",但是如果.不可解析,则让strptime/1错误,并且可能想返回不可解析的输入(通过catch (.)对其具有微妙的效果)。为什么不尝试解析日期并返回到无法解析的输入,而不管特殊情况如何?

  • 如果您打算创建特殊情况,为什么不让它为if type == "string"?毕竟,这是馈送strptime/1的唯一有意义的类型(即使它可能不包含可解析的日期)。

  • 默认为不可解析的输入时,输出类型/模式变得不可预测,但这也许对您来说还可以。

  • “最后”部分建议通过在.release_date中内联try来表明此字段是可选的。我不知道您是否打算表示可能是这种情况,所以我选择假设不会,因为未指定。

jq 1.5

这是一个简化的示例,其中删除了一些对象属性:

$ jq -c '.[]' release_date.json 
{"id":"42","release_date":"2019-12-31"}
{"id":"42","release_date":null}
{"id":"42","release_date":"SOON!"}

$ jq 'map(.release_date |= . as $date | try (strptime("%Y-%m-%d") | mktime) catch $date)' release_date.json   
[
  {
    "id": "42",
    "release_date": 1577750400
  },
  {
    "id": "42",
    "release_date": null
  },
  {
    "id": "42",
    "release_date": "SOON!"
  }
]

catch块中,.表示字符串化的异常,因此默认为不可解析的值,它暂时称为$date。或使用带有$value参数的user-defined function

$ jq 'def parsedate($date):
        try ($date | strptime("%Y-%m-%d") | mktime)
        catch $date;

        map(.release_date |= parsedate(.))' release_date.json

jq 1.6

有趣的是,以上解决方案不适用于jq 1.6。

我尝试将差异缩小到最小。

https://jqplay.org/s/M_RpdNHvHF

$ jq-1.6 '. |= try . catch .' <<< 1
{
  "__jq": 0
}

在这种意外的行为更改之前,避免同时使用|=try-catch是一种可行的选择:

https://jqplay.org/s/ki8I1YnU56

$ jq 'map(.release_date = (.release_date | . as $date
            | try (strptime("%Y-%m-%d") | mktime) catch $date))' release_date.json

https://jqplay.org/s/i4FJPpXEG0

$ jq 'def parsedate($date):
        try ($date | strptime("%Y-%m-%d") | mktime)
        catch $date;

      map(.release_date = parsedate(.release_date))' release_date.json

我已经举报了here

答案 1 :(得分:1)

简而言之,jq 1.6引入了一个错误,该错误影响了|=上下文中对catch / try的处理。

在当前情况下,最简单的解决方法是避免使用|=,例如通过:


(.release_date
    | try (if . == null or . == ""
           then . 
           else strptime("%Y-%m-%d") | mktime end)
     catch .) as $r
  | .release_date = $r'

请注意,. |子句中不需要初始的else