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

Ste*_*ige 4 regex url json 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"
  }
]
Run Code Online (Sandbox Code Playgroud)

我正在寻找使用jq创建另一个文件,仅当 url 的值与某个模式匹配时才修改 url。例如,我想更新任何与模式匹配的网址:

http://otherdomain.com.*filenameB.*
Run Code Online (Sandbox Code Playgroud)

到一些固定的字符串,例如:

http://yetanotherdomain.com/new/path/to/filenameC.tar.gz
Run Code Online (Sandbox Code Playgroud)

生成的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"
  }
]
Run Code Online (Sandbox Code Playgroud)

我什至无法找到网址,更不用说更新它了。这是我得到的(错误的结果,并不能帮助我解决更新问题):

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

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

pea*_*eak 5

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

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)
Run Code Online (Sandbox Code Playgroud)

不太好的消息是,除非您了解这里的关键技巧——“|=”过滤器,否则它并不容易解释。有很多关于它的 jq 文档,所以我只是指出它类似于 C 系列编程语言中的 += 运算符系列。

具体来说,.url |= sub(A;B)就像.url = (.url|sub(A;B)). 这就是“就地”完成更新的方式。