jq:如何根据子字符串匹配更新值?

时间:2016-01-29 13:51:32

标签: json url string-matching jq

我有一个 jq 问题。给定文件 file.json 包含:

[
  {
    "type": "A",
    "name": "name 1",
    "url": "http://domain.com/path/to/filenameA.zip"
  },
  {
    "type": "B",
    "name": "name 2",
    "url": "http://domain.com/otherpath/to/filenameB.zip"
  },
  {
    "type": "C",
    "name": "name 3",
    "url": "http://otherdomain.com/otherpath/to/filenameB.zip"
  }
]

我希望使用 jq 创建另一个文件,只有当url的值与某个模式匹配时才会修改url。例如,我想更新与模式匹配的任何网址:

http://otherdomain.com.*filenameB.*

到某些固定字符串,例如:

http://yetanotherdomain.com/new/path/to/filenameC.tar.gz

生成的json:

[
  {
    "type": "A",
    "name": "name 1",
    "url": "http://domain.com/path/to/filenameA.zip"
  },
  {
    "type": "B",
    "name": "name 2",
    "url": "http://domain.com/otherpath/to/filenameB.zip"
  },
  {
    "type": "C",
    "name": "name 3",
    "url": "http://yetanotherdomain.com/new/path/to/filenameB.tar.gz"
  }
]

即使能够找到网址,我也无法获得更多信息,更不用说更新网址了。这是我得到的(错误的结果,并没有帮助我解决更新问题):

% cat file.json | jq -r '.[] | select(.url | index("filenameB")).url'
http://domain.com/otherpath/to/filenameB.zip
http://otherdomain.com/otherpath/to/filenameB.zip
%

有关如何获取具有与正则表达式匹配的值的键的路径的任何想法?之后,如何使用一些新的字符串值更新密钥?如果有多个匹配项,则应使用相同的新值更新所有匹配项。

2 个答案:

答案 0 :(得分:3)

好消息是,这个问题的解决方案很简单:

map( if .url | test("http://otherdomain.com.*filenameB.*")
     then .url |= sub(  "http://otherdomain.com.*filenameB.*"; 
           "http://yetanotherdomain.com/new/path/to/filenameC.tar.gz")
     else .
     end)

不太好的消息是,除非你理解这里的关键聪明 - " | ="否则解释起来并不容易。过滤。有很多关于它的jq文档,所以我只是指出它类似于C系列编程语言中的+ =运算符族。

具体而言,.url |= sub(A;B).url = (.url|sub(A;B))类似。这就是更新如何完成"就地"。

答案 1 :(得分:1)

此解决方案使用 tostream 选择标识网址成员的路径,然后使用 reduce setpath更新值

WITH three_values(x) AS
(
VALUES 
   (NULL), (FALSE), (TRUE)
)
SELECT
   a, b, 
   a = NULL AS a_equals_null,  -- This is alwaus NULL
   a IS NULL AS a_is_null,     -- This is NEVER NULL
   a OR  b AS a_or_b,          -- This is UNKNOWN if both are
   a AND b AS a_and_b,         -- This is UNKNOWN if any is
   NOT a   AS not_a,           -- This is UNKNOWN if a is
   (a OR b) AND NOT (a AND b) AS a_xor_b,   -- Unknown when any is unknown
   /* (a AND NOT b) OR (NOT a AND b) a_xor_b_v2, */
   NOT a OR b  AS a_implies_b  -- Kleener and Priests logic
FROM
   three_values AS x(a)
   CROSS JOIN
   three_values AS y(b);