使用 JQ 从不同目录获取 json 字段值

Get json field value with JQ from different directory

标题可能不正确,因为我不确定这是哪里失败了。我在一个目录中有一个 bash 脚本 运行,在另一个目录中有一个 JSON 文件,我需要一个值。我想将外部目录中的值复制到当前目录中的相同 JSON 文件中。

我正在使用 jq 获取值,但我不知道如何从脚本 运行 所在的目录以外的目录中获取值。

文件结构的相关位如下;

cloudformation
  - parameters_v13.json
environment_files
  - prepare_stack_files.json (the script this is run from)
  - directory, changes based on where the script is pointed
      - created directory where created files are being output
         - GREPNAME_parameters.json

我感兴趣的 JSON 文件块如下所示;

[ 
{
   "ParameterKey": "RTSMEMAIL",
   "ParameterValue": "secretemail"
  }
]

脚本需要从 cloudformation/parameters_v13.json 中获取 "secretemail" 并将其粘贴到 GREPNAME_parameters.json 文件中匹配的 RTSMEMAIL 字段中。

我一直在尝试以下操作,但没有成功 - 没有任何输出。也没有错误消息,只是空白输出。我知道 GREPNAME 路径是正确的,因为它在其他地方使用没有问题。

jq --arg email "$EMAIL" '(.[] | select(.ParameterKey == "RTSMEMAIL") | .ParameterValue) |= $email' ../cloudformation/parameters_v13.json | sponge ${GREPNAME}_parameters.json

这个 jq 过滤器应该可以帮助您获得 secretmail 字符串

jq '.[] | select(.ParameterKey=="RTSMEMAIL") | .ParameterValue' json
"secretemail"

为原始输出添加一个 -r 文件以删除值周围的引号

jq -r '.[] | select(.ParameterKey=="RTSMEMAIL") | .ParameterValue' json
secretemail

--raw-output / -r:

With this option, if the filter’s result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems.

如我所见,您正在尝试将 args 传递给 jq 过滤器,对于提取,您可以先通过在 bash

中设置变量来做一些事情
email="RTSMEMAIL"

现在将它作为

传递给过滤器
jq --arg email "$email" -r '.[] | select(.ParameterKey==$email) | .ParameterValue' json 
secretemail

现在要将从 parameters_v13.json 文件中获取的字符串替换为您的 GREPNAME_parameters.json,请执行以下步骤:-

首先将第一个文件的结果存储在一个变量中以便稍后重新使用,我使用该文件提取为 json,这实际上将您的 parameters_v13.json 文件指向另一个路径。

replacementValue=$(jq --arg email "$email" -r '.[] | select(.ParameterKey==$email) | .ParameterValue' json)

现在 $replacementValue 将包含您要更新到另一个文件的 secretmail。正如您之前指出的那样,GREPNAME_parameters.json 与第一个文件具有相似的语法。如下所示,

$ cat GREPNAME_parameters.json
[ 
{
   "ParameterKey": "SOMEJUNK",
   "ParameterValue": "somejunkvalue"
  }
]

现在我明白您的意图是将上述文件中的 "ParameterValue" 替换为从其他文件中获取的值。为此,

jq --arg replace "$replacementValue" '.[] | .ParameterValue = $replace' GREPNAME_parameters.json
{
  "ParameterKey": "SOMEJUNK",
  "ParameterValue": "secretemail"
}

然后您可以将此输出写入临时文件并将其作为 GREPNAME_parameters.json 移回。希望这能回答您的问题。

@Alex -

(1) sponge 只是提供了一种无需管理临时文件即可修改文件的便捷方法。你可以这样使用它:

jq  ........ input.json | sponge input.json

这里"input.json"是你要编辑的文件"in place"。如果你想避免覆盖输入文件,你不会使用 sponge。事实上,我建议不要这样做,直到你完全确定那是你想要的。

(2) 有几种策略可以使用 jq 实现您所描述的内容。它们基本上分为两类:(a) 调用 jq 两次; (b) 调用 jq 一次。

忽略 sponge 部分:

  • 两次使用jq的模式如下:

    param=$(jq -r '.[]
      | select(.ParameterKey == "RTSMEMAIL")|.ParameterValue
      ' cloudformation/parameters_v13.json )
    
    jq --arg param "$param" -f edit.jq input.json
    
  • 假设您有 jq 1.5,只需调用一次 jq 即可完成所有操作的模式为:

    jq --argfile p cloudformation/parameters_v13.json -f manage.jq input.json
    

这里,edit.jq和manage.jq是包含合适的jq程序的文件。

根据我对您的要求的理解,edit.jq 可能如下所示:

(.[] | select(.ParameterKey == "RTSMEMAIL")|.ParameterValue) |= $param

而 manage.jq 可能看起来像这样:

($p[] | select(.ParameterKey == "RTSMEMAIL")|.ParameterValue) as $param
| (.[]| select(.ParameterKey == "RTSMEMAIL")|.ParameterValue) |= $param