【问题标题】:Bash JSON compare two list and delete idBash JSON比较两个列表并删除id
【发布时间】:2021-12-03 14:40:41
【问题描述】:

我有一个 JSON 端点,我可以使用 curl 和 yml 本地文件获取值。我想获取差异并使用 JSON 端点上存在的名称 id 将其删除。

JSON 的端点

[
  {
    "hosts": [
      "server1"
    ],
    "id": "qz9o847b-f07c-49d1-b1fa-e5ed0b2f0519",
    "name": "V1_toto_a"
  },
  {
    "hosts": [
      "server2"
    ],
    "id": "a6aa847b-f07c-49d1-b1fa-e5ed0b2f0519",
    "name": "V1_tata_b"
  },
  {
    "hosts": [
      "server3"
    ],
    "id": "a6d9ee7b-f07c-49d1-b1fa-e5ed0b2f0519",
    "name": "V1_titi_c"
  }
]

文件.yml

---
instance:
  toto:
    name: "toto"
  tata:
    name: "tata"

在JSON的端点和本地文件之间,我想用tata的id删除它,因为它是源之间的差异。

declare -a arr=(_a _b _c)
ar=$(cat files.yml | grep name | cut -d '"' -f2 | tr "\n" " ")
fileItemArray=($ar)
ARR_PRE=("${fileItemArray[@]/#/V1_}")
for i in "${arr[@]}"; do local_var+=("${ARR_PRE[@]/%/$i}"); done
remote_var=$(curl -sX GET "XXXX" | jq -r '.[].name | @sh' | tr -d \'\")
diff_=$(echo ${local_var[@]} ${remote_var[@]} | tr ' ' '\n' | sort | uniq -u)

输出=titi

代码有效,但我想动态删除带有 id 的titi

curl -X DELETE "XXXX" $id_titi

我正在尝试使用 bash 脚本删除,但我不知道继续...

【问题讨论】:

    标签: json bash jq


    【解决方案1】:

    您的端点不是正确的 JSON,因为它有

    • .name 字段后面的逗号,但没有后续字段
    • 顶级数组的元素之间没有逗号

    如果这不仅仅是将您的示例粘贴到此问题中的拼写错误,那么您需要先解决此问题,然后再继续。它应该是这样的:

    [
      {
        "hosts": [
          "server1"
        ],
        "id": "qz9o847b-f07c-49d1-b1fa-e5ed0b2f0519",
        "name": "toto"
      },
      {
        "hosts": [
          "server2"
        ],
        "id": "a6aa847b-f07c-49d1-b1fa-e5ed0b2f0519",
        "name": "tata"
      },
      {
        "hosts": [
          "server3"
        ],
        "id": "a6d9ee7b-f07c-49d1-b1fa-e5ed0b2f0519",
        "name": "titi"
      }
    ]
    

    如果您的端点是正确的 JSON,请尝试以下操作。它从您的 .yml 文件中提取名称(就像您所做的那样 - 有很多更有效且不易出错的方法,但我正在尝试尽可能多地调整您的方法),而不是 Bash 数组生成 JSON使用jq 的数组,这对于 Bash 是一个简单的字符串。对于您的curl 输出,它基本上是相同的,将名称的(JSON)数组提取到 Bash 字符串中。请注意,在这两种情况下,我都使用引号<var>="$(…)" 来捕获可能包含空格的字符串(尽管我也使用jq 的-c 选项将其输出压缩为一行)。对于两者之间的区别,一切都由jq 接管,因为它可以很容易地将 JSON 数组作为变量提供,执行减法并以您喜欢的格式输出:

    fromyml="$(cat files.yml | grep name | cut -d '"' -f2 | jq -Rnc '[inputs]')"
    fromcurl="$(curl -sX GET "XXXX" | jq -c 'map(.name)')"
    diff="$(jq -nr --argjson fromyml "$fromyml" --argjson fromcurl "$fromcurl" '
      $fromcurl - $fromyml | .[]
    ')"
    

    Bash 变量 diff 现在包含一个仅出现在 curl 输出 ($fromcurl - $fromyml) 中的名称列表,每行一个(如果在您的示例之外,碰巧不止一个)。如果 curl 输出有重复,它们仍然会被包含(使用$fromcurl - $fromyml | unique | .[] 删除它们):

    titi
    

    如您所见,此解决方案对jq 进行了三个调用。我会把它留给你来进一步减少这个数字,因为它适合你的一般工作流程(基本上,它可以合二为一)。

    【讨论】:

    • 感谢您的回复,但我编辑了这个问题,因为我在数组上添加了一些操作字符串。最后,我想删除带有id的titi实例。
    • 该编辑改变了整个工作流程设计,因为您需要将相应的 id 与名称一起携带,以便按一个过滤并最终输出另一个。当然,仅考虑 name(s) 的当前输出,您还可以使用它在 curl 的输出内容中通过另一个 jq 调用来查询它们的 id,但是重新设计将是从在这里imo。
    【解决方案2】:

    可以使用read 将程序的输出转换为变量。

    perl -M5.010 -MYAML -MJSON::PP -e'
       sub get_next_file { local $/; "".<> }
       my %filter = map { $_->{name} => 1 } values %{ Load(get_next_file)->{instance} };
       say for grep !$filter{$_}, map $_->{name}, @{ decode_json(get_next_file) };
    ' b.yaml a.json |
    while IFS= read -r id; do
       curl -X DELETE ..."$id"...
    done
    

    我在这里使用 Perl 是因为您无法解析 YAML 文件。 sn-p 需要安装 YAML Perl 模块。

    【讨论】:

    • 感谢您的回复,但我编辑了这个问题,因为我在数组上添加了一些操作字符串。最后,我想删除带有id的titi实例。
    • 我想你是说你想在脚本变量中使用titi?使用read。查看更新。
    • 不,我要获取titi的id,这样我可以删除
    • 什么意思?您的问题表明您想使用 id 构建 curl 请求,而我的回答显示了如何做到这一点。将printf 'Do something with %s\n' "$id" 替换为适当的curl 命令。
    猜你喜欢
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    相关资源
    最近更新 更多