首页 > 解决方案 > jq 查询返回太多记录(不需要的排列)

问题描述

我有一个复杂的 JSON 文件,我正在尝试使用 JQ 获得以下结果。

预期结果:

{
  "Host": "Test.example.com",
  "Title": "Ensure message of the day is configured properly",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure bond0 is present",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure the SELinux state is disabled",
  "Status": "passed"
}

下面是我通过运行 Chef Inspec 配置文件得到的 JSON 文件。

JSON文件:

{
  "platform": {
    "name": "redhat",
    "release": "7.7",
    "target_id": "Test.example.com"
  },
  "profiles": [
    {
      "name": "my-test",
      "version": "0.1.0",
      "sha256": "6fea36d6c12b21cd51274774edb4200d983db45c4cfa8172eebb897b6f3db8fe",
      "title": "InSpec Profile",
      "maintainer": "The Authors",
      "summary": "An InSpec Compliance Profile",
      "license": "Apache-2.0",
      "copyright": "The Authors",
      "copyright_email": "you@example.com",
      "supports": [
        {
          "platform": "os"
        }
      ],
      "attributes": [],
      "groups": [
        {
          "id": "controls/1_motd.rb",
          "controls": [
            "1.1 motd check"
          ],
          "title": "Warning Banners"
        },
        {
          "id": "controls/6_network.rb",
          "controls": [
            "6.1 Bonding"
          ]
        },
        {
          "id": "controls/12_selinux.rb",
          "controls": [
            "Selinux Config"
          ]
        }
      ],
      "controls": [
        {
          "id": "1.1 motd check",
          "title": "Ensure message of the day is configured properly",
          "desc": "Ensure message of the day is configured properly",
          "descriptions": [
            {
              "label": "default",
              "data": "Ensure message of the day is configured properly"
            }
          ],
          "impact": 1,
          "refs": [],
          "tags": {},
          "code": "control '1.1 motd check' do\n  title 'Ensure message of the day is configured properly'\n  desc  \"The contents of the /etc/motd file are displayed to users after login and function as a message of the day for authenticated users.\"\n  desc \"Ensure message of the day is configured properly\"\n  impact 1.0\n  \n  describe file('/etc/motd') do\n    its('content') { should_not be_empty }\n  end\nend\n",
          "source_location": {
            "line": 3,
            "ref": "my-test/controls/1_motd.rb"
          },
          "waiver_data": {},
          "results": [
            {
              "status": "passed",
              "code_desc": "File /etc/motd content should not be empty",
              "run_time": 0.099938054,
              "start_time": "2020-02-07T11:31:47+11:00"
            }
          ]
        },
        {
          "id": "6.1 Bonding",
          "title": "Ensure bond0 is present",
          "desc": "Check bonding is present",
          "descriptions": [
            {
              "label": "default",
              "data": "Check bonding is present"
            }
          ],
          "impact": 1,
          "refs": [],
          "tags": {},
          "code": "control '6.1 Bonding' do\n  title 'Ensure bond0 is present'\n  desc  \"Check bonding is present\"\n  impact 1.0\n  \n  only_if { sys_info.manufacturer != \"VMware, Inc.\" } \n\n  describe bond('bond0') do\n    it { should exist }\n    its('mode') { should eq 'IEEE 802.3ad Dynamic link aggregation' }\n  end\nend\n",
          "source_location": {
            "line": 1,
            "ref": "my-test/controls/6_network.rb"
          },
          "waiver_data": {},
          "results": [
            {
              "status": "skipped",
              "code_desc": "No-op",
              "run_time": 9.02e-06,
              "start_time": "2020-02-07T11:31:47+11:00",
              "resource": "No-op",
              "skip_message": "Skipped control due to only_if condition."
            }
          ]
        },
        {
          "id": "Selinux Config",
          "title": "Ensure the SELinux state is disabled",
          "desc": "Set SELinux to diabled",
          "descriptions": [
            {
              "label": "default",
              "data": "Set SELinux to diabled"
            }
          ],
          "impact": 1,
          "refs": [],
          "tags": {},
          "code": "control 'Selinux Config' do\n  title 'Ensure the SELinux state is disabled'\n  desc  \"Set SELinux to diabled\"\n  impact 1.0\n\n    describe file('/etc/selinux/config') do\n    its(:content) { should match(/^SELINUX=disabled\\s*(?:#.*)?$/) }\n  end\nend\n",
          "source_location": {
            "line": 1,
            "ref": "my-test/controls/12_selinux.rb"
          },
          "waiver_data": {},
          "results": [
            {
              "status": "passed",
              "code_desc": "File /etc/selinux/config content should match /^SELINUX=disabled\\s*(?:#.*)?$/",
              "run_time": 0.120881444,
              "start_time": "2020-02-07T11:31:47+11:00"
            }
          ]
        }
      ],
      "status": "loaded"
    }
  ],
  "statistics": {
    "duration": 0.223533139
  },
  "version": "4.18.24"
}

我使用以下 JQ 代码来提取字段,但提取的值是重复的。

JQ代码:

jq  '{Host: .platform.target_id,Title: .profiles[].controls[].title,Status: .profiles[].controls[].results[].status}'

我从上面的 JQ 过滤器得到的结果

实际结果:

{
  "Host": "Test.example.com",
  "Title": "Ensure message of the day is configured properly",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure message of the day is configured properly",
  "Status": "skipped"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure message of the day is configured properly",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure bond0 is present",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure bond0 is present",
  "Status": "skipped"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure bond0 is present",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure the SELinux state is disabled",
  "Status": "passed"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure the SELinux state is disabled",
  "Status": "skipped"
}
{
  "Host": "Test.example.com",
  "Title": "Ensure the SELinux state is disabled",
  "Status": "passed"
}

我怎样才能得到预期的结果。任何帮助,将不胜感激。

标签: jsoniterationjq

解决方案


因为您profiles[]不止一次地迭代,所以您将一个这样的迭代的结果与另一个迭代的结果相结合。为避免这种情况,只迭代一次,titleresults从同一个controls列表条目中获取两者。

jq  '
.platform.target_id as $target |
.profiles[].controls[] |
{ Host: $target,
  Title: .title,
  Status: .results[].status }
'

在https://jqplay.org/s/_6KVDfIn3m上查看针对您的输入数据的运行情况


推荐阅读