简体   繁体   English

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

[英]jq: how do I update a value based on a substring match?

I've got a jq question.我有一个jq问题。 Given a file file.json containing:给定文件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"
  }
]

I'm looking to create another file using jq with url modified only if the url's value matches some pattern.我正在寻找使用jq创建另一个文件,仅当 url 的值与某个模式匹配时才修改 url。 For example, I'd want to update any url matching the pattern:例如,我想更新任何与模式匹配的网址:

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

to some fixed string such as:到一些固定的字符串,例如:

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

with the resulting json:生成的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"
  }
]

I haven't gotten far even on being able to find the url, let alone update it.我什至无法找到网址,更不用说更新它了。 This is as far as I've gotten (wrong results and doesn't help me with the update issue):这是我得到的(错误的结果,并不能帮助我解决更新问题):

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

Any ideas on how to get the path of the key that has a value matching a regex?关于如何获取具有与正则表达式匹配的值的键的路径的任何想法? And after that, how to update the key with some new string value?之后,如何用一些新的字符串值更新键? If there are multiple matches, all should be updated with the same new value.如果有多个匹配项,则所有匹配项都应使用相同的新值进行更新。

The good news is that there's a simple solution to the problem:好消息是,这个问题有一个简单的解决方案:

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)

The not-so-good news is that it's not so easy to explain unless you understand the key cleverness here - the "|=" filter.不太好的消息是,除非您了解这里的关键技巧——“|=”过滤器,否则它并不容易解释。 There is plenty of jq documentation about it, so I'll just point out that it is similar to the += family of operators in the C family of programming languages.有很多关于它的 jq 文档,所以我只是指出它类似于 C 系列编程语言中的 += 运算符系列。

Specifically, .url |= sub(A;B) is like .url = (.url|sub(A;B)) .具体来说, .url |= sub(A;B)就像.url = (.url|sub(A;B)) That is how the update is done "in-place".这就是“就地”完成更新的方式。

Here is a solution which identifies paths to url members with tostream and select and then updates the values using reduce and setpath这是一个解决方案,它使用tostreamselect识别 url 成员的路径,然后使用reducesetpath更新值

  "http://otherdomain.com.*filenameB.*"                      as $from
| "http://yetanotherdomain.com/new/path/to/filenameC.tar.gz" as $to

| reduce (tostream | select(length == 2 and .[0][-1] == "url")) as $p (
      .
    ; setpath($p[0]; $p[1] | sub($from; $to))
  )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM