[json] jq를 사용하여 JSON 문자열을 테이블로 포맷하는 방법은 무엇입니까?

방금 Bash 스크립팅으로 시작하여 JSON으로 작업하기 위해 jq를 우연히 발견했습니다.

터미널에서 출력하기 위해 아래와 같은 JSON 문자열을 테이블로 변환해야합니다.

[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]

터미널에 표시 할 내용 :

ID        Name
=================
12        George
18        Jack
19        Joe

각 행에 대해 이메일 속성을 표시하지 않으려는 경우 jq 명령에 일부 필터링이 포함되어야합니다. 다음은 이름과 ID의 일반 목록을 제공합니다.

list=$(echo "$data" | jq -r '.[] | .name, .id')
printf "$list"

문제는 표처럼 표시 할 수 없다는 것입니다. jq에는 몇 가지 형식 지정 옵션이 있지만을 사용할 때 사용하는 옵션만큼 좋지는 않습니다 printf. 이 값을 배열로 가져 와서 형식화를 수행 할 수 있습니다 …? 내가 시도한 것들은 나에게 다양한 결과를 제공하지만 내가 정말로 원하는 것은 결코 아닙니다.

누군가 나를 올바른 방향으로 가리킬 수 있습니까?



답변

다음과 같은 이유는 무엇입니까?

echo '[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]' | jq -r '.[] | "\(.id)\t\(.name)"'

산출

12  George
18  Jack
19  Joe

편집 1 : 세밀한 서식 지정을 위해 다음과 같은 도구를 사용하십시오.awk

 echo '[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]' | jq -r '.[] | [.id, .name] | @csv' | awk -v FS="," 'BEGIN{print "ID\tName";print "============"}{printf "%s\t%s%s",$1,$2,ORS}'
ID  Name
============
12  "George"
18  "Jack"
19  "Joe"

편집 2 : 회신

jq에서 직접 배열을 포함하는 변수를 얻을 수있는 방법이 없습니까?

왜 안돼?

이메일이 배열로 변경된 약간 관련된 예제 (사실 당신의 것에서 수정 됨)는 이것을 보여줍니다

echo '[{
    "name": "George",
    "id": 20,
    "email": [ "george@domain1.com" , "george@domain2.com" ]
}, {
    "name": "Jack",
    "id": 18,
    "email": [ "jack@domain3.com" , "jack@domain5.com" ]
}, {
    "name": "Joe",
    "id": 19,
    "email": [ "joe@domain.com" ]
}]' | jq -r '.[] | .email'

산출

[
  "george@domain1.com",
  "george@domain2.com"
]
[
  "jack@domain3.com",
  "jack@domain5.com"
]
[
  "joe@domain.com"
]


답변

@tsv필터를 사용하면 권장 할 사항이 많습니다. 주로 표준 방식으로 수많은 “에지 케이스”를 처리하기 때문입니다.

.[] | [.id, .name] | @tsv

헤더 추가는 다음과 같이 수행 할 수 있습니다.

jq -r '["ID","NAME"], ["--","------"], (.[] | [.id, .name]) | @tsv'

결과:

ID  NAME
--  ------
12  George
18  Jack
19  Joe

length*"-"

대시 라인 생산을 자동화하려면 :

jq -r '(["ID","NAME"] | (., map(length*"-"))), (.[] | [.id, .name]) | @tsv'


답변

헤더를 직접 정의하는 것은 차선책입니다! 헤더를 생략하는 것도 차선책입니다.

TL; DR

데이터

[{ "name": "George", "id": 12, "email": "george@domain.com" },
{ "name": "Jack", "id": 18, "email": "jack@domain.com" },
{ "name": "Joe", "id": 19, "email": "joe@domain.com" }]

스크립트

  [.[]| with_entries( .key |= ascii_downcase ) ]
      |    (.[0] |keys_unsorted | @tsv)
         , (.[]|.|map(.) |@tsv)

달리는 방법

$ < data jq -rf script  | column -t
name    id  email
George  12  george@domain.com
Jack    18  jack@domain.com
Joe     19  joe@domain.com

아마존 웹 서비스의 일부 데이터를 요약하는 동안이 질문을 발견했습니다. 다른 예를 원할 경우 내가 작업하고 있던 문제 :

$ aws ec2 describe-spot-instance-requests | tee /tmp/ins |
    jq  --raw-output '
                                     # extract instances as a flat list.
    [.SpotInstanceRequests | .[]
                                     # remove unwanted data
    | {
        State,
        statusCode: .Status.Code,
        type: .LaunchSpecification.InstanceType,
        blockPrice: .ActualBlockHourlyPrice,
        created: .CreateTime,
        SpotInstanceRequestId}
    ]
                                        # lowercase keys
                                        # (for predictable sorting, optional)
    |  [.[]| with_entries( .key |= ascii_downcase ) ]
        |    (.[0] |keys_unsorted | @tsv)               # print headers
           , (.[]|.|map(.) |@tsv)                       # print table
    ' | column -t

산출:

state      statuscode                   type     blockprice  created                   spotinstancerequestid
closed     instance-terminated-by-user  t3.nano  0.002000    2019-02-24T15:21:36.000Z  sir-r5bh7skq
cancelled  bad-parameters               t3.nano  0.002000    2019-02-24T14:51:47.000Z  sir-1k9s5h3m
closed     instance-terminated-by-user  t3.nano  0.002000    2019-02-24T14:55:26.000Z  sir-43x16b6n
cancelled  bad-parameters               t3.nano  0.002000    2019-02-24T14:29:23.000Z  sir-2jsh5brn
active     fulfilled                    t3.nano  0.002000    2019-02-24T15:37:26.000Z  sir-z1e9591m
cancelled  bad-parameters               t3.nano  0.002000    2019-02-24T14:33:42.000Z  sir-n7c15y5p

입력:

$ cat /tmp/ins
{
    "SpotInstanceRequests": [
        {
            "Status": {
                "Message": "2019-02-24T15:29:38+0000 : 2019-02-24T15:29:38+0000 : Spot Instance terminated due to user-initiated termination.",
                "Code": "instance-terminated-by-user",
                "UpdateTime": "2019-02-24T15:31:03.000Z"
            },
            "ActualBlockHourlyPrice": "0.002000",
            "ValidUntil": "2019-03-03T15:21:36.000Z",
            "InstanceInterruptionBehavior": "terminate",
            "Tags": [],
            "InstanceId": "i-0414083bef5e91d94",
            "BlockDurationMinutes": 60,
            "SpotInstanceRequestId": "sir-r5bh7skq",
            "State": "closed",
            "ProductDescription": "Linux/UNIX",
            "LaunchedAvailabilityZone": "eu-north-1a",
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default",
                    "AvailabilityZone": "eu-north-1a"
                },
                "ImageId": "ami-6d27a913",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1",
                        "VirtualName": "root",
                        "NoDevice": "",
                        "Ebs": {
                            "Encrypted": false,
                            "DeleteOnTermination": true,
                            "VolumeType": "gp2",
                            "VolumeSize": 8
                        }
                    }
                ],
                "EbsOptimized": false,
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ],
                "Monitoring": {
                    "Enabled": false
                },
                "InstanceType": "t3.nano",
                "AddressingType": "public",
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Description": "eth-zero",
                        "NetworkInterfaceId": "",
                        "DeleteOnTermination": true,
                        "SubnetId": "subnet-420ffc2b",
                        "AssociatePublicIpAddress": true
                    }
                ]
            },
            "Type": "one-time",
            "CreateTime": "2019-02-24T15:21:36.000Z",
            "SpotPrice": "0.008000"
        },
        {
            "Status": {
                "Message": "Your Spot request failed due to bad parameters.",
                "Code": "bad-parameters",
                "UpdateTime": "2019-02-24T14:51:48.000Z"
            },
            "ActualBlockHourlyPrice": "0.002000",
            "ValidUntil": "2019-03-03T14:51:47.000Z",
            "InstanceInterruptionBehavior": "terminate",
            "Tags": [],
            "Fault": {
                "Message": "Invalid device name /dev/sda",
                "Code": "InvalidBlockDeviceMapping"
            },
            "BlockDurationMinutes": 60,
            "SpotInstanceRequestId": "sir-1k9s5h3m",
            "State": "cancelled",
            "ProductDescription": "Linux/UNIX",
            "LaunchedAvailabilityZone": "eu-north-1a",
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default",
                    "AvailabilityZone": "eu-north-1a"
                },
                "ImageId": "ami-6d27a913",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda",
                        "VirtualName": "root",
                        "NoDevice": "",
                        "Ebs": {
                            "Encrypted": false,
                            "DeleteOnTermination": true,
                            "VolumeType": "gp2",
                            "VolumeSize": 8
                        }
                    }
                ],
                "EbsOptimized": false,
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ],
                "Monitoring": {
                    "Enabled": false
                },
                "InstanceType": "t3.nano",
                "AddressingType": "public",
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Description": "eth-zero",
                        "NetworkInterfaceId": "",
                        "DeleteOnTermination": true,
                        "SubnetId": "subnet-420ffc2b",
                        "AssociatePublicIpAddress": true
                    }
                ]
            },
            "Type": "one-time",
            "CreateTime": "2019-02-24T14:51:47.000Z",
            "SpotPrice": "0.011600"
        },
        {
            "Status": {
                "Message": "2019-02-24T15:02:17+0000 : 2019-02-24T15:02:17+0000 : Spot Instance terminated due to user-initiated termination.",
                "Code": "instance-terminated-by-user",
                "UpdateTime": "2019-02-24T15:03:34.000Z"
            },
            "ActualBlockHourlyPrice": "0.002000",
            "ValidUntil": "2019-03-03T14:55:26.000Z",
            "InstanceInterruptionBehavior": "terminate",
            "Tags": [],
            "InstanceId": "i-010442ac3cc85ec08",
            "BlockDurationMinutes": 60,
            "SpotInstanceRequestId": "sir-43x16b6n",
            "State": "closed",
            "ProductDescription": "Linux/UNIX",
            "LaunchedAvailabilityZone": "eu-north-1a",
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default",
                    "AvailabilityZone": "eu-north-1a"
                },
                "ImageId": "ami-6d27a913",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1",
                        "VirtualName": "root",
                        "NoDevice": "",
                        "Ebs": {
                            "Encrypted": false,
                            "DeleteOnTermination": true,
                            "VolumeType": "gp2",
                            "VolumeSize": 8
                        }
                    }
                ],
                "EbsOptimized": false,
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ],
                "Monitoring": {
                    "Enabled": false
                },
                "InstanceType": "t3.nano",
                "AddressingType": "public",
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Description": "eth-zero",
                        "NetworkInterfaceId": "",
                        "DeleteOnTermination": true,
                        "SubnetId": "subnet-420ffc2b",
                        "AssociatePublicIpAddress": true
                    }
                ]
            },
            "Type": "one-time",
            "CreateTime": "2019-02-24T14:55:26.000Z",
            "SpotPrice": "0.011600"
        },
        {
            "Status": {
                "Message": "Your Spot request failed due to bad parameters.",
                "Code": "bad-parameters",
                "UpdateTime": "2019-02-24T14:29:24.000Z"
            },
            "ActualBlockHourlyPrice": "0.002000",
            "ValidUntil": "2019-03-03T14:29:23.000Z",
            "InstanceInterruptionBehavior": "terminate",
            "Tags": [],
            "Fault": {
                "Message": "Addressing type must be 'public'",
                "Code": "InvalidParameterCombination"
            },
            "BlockDurationMinutes": 60,
            "SpotInstanceRequestId": "sir-2jsh5brn",
            "State": "cancelled",
            "ProductDescription": "Linux/UNIX",
            "LaunchedAvailabilityZone": "eu-north-1a",
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default",
                    "AvailabilityZone": "eu-north-1a"
                },
                "ImageId": "ami-6d27a913",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda",
                        "VirtualName": "root",
                        "NoDevice": "",
                        "Ebs": {
                            "Encrypted": false,
                            "DeleteOnTermination": true,
                            "VolumeType": "gp2",
                            "VolumeSize": 8
                        }
                    }
                ],
                "EbsOptimized": false,
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ],
                "Monitoring": {
                    "Enabled": false
                },
                "InstanceType": "t3.nano",
                "AddressingType": "",
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Description": "eth-zero",
                        "NetworkInterfaceId": "",
                        "DeleteOnTermination": true,
                        "SubnetId": "subnet-420ffc2b",
                        "AssociatePublicIpAddress": true
                    }
                ]
            },
            "Type": "one-time",
            "CreateTime": "2019-02-24T14:29:23.000Z",
            "SpotPrice": "0.011600"
        },
        {
            "Status": {
                "Message": "Your spot request is fulfilled.",
                "Code": "fulfilled",
                "UpdateTime": "2019-02-24T15:37:28.000Z"
            },
            "ActualBlockHourlyPrice": "0.002000",
            "ValidUntil": "2019-03-03T15:37:26.000Z",
            "InstanceInterruptionBehavior": "terminate",
            "Tags": [],
            "InstanceId": "i-0a29e9de6d59d433f",
            "BlockDurationMinutes": 60,
            "SpotInstanceRequestId": "sir-z1e9591m",
            "State": "active",
            "ProductDescription": "Linux/UNIX",
            "LaunchedAvailabilityZone": "eu-north-1a",
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default",
                    "AvailabilityZone": "eu-north-1a"
                },
                "ImageId": "ami-6d27a913",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1",
                        "VirtualName": "root",
                        "NoDevice": "",
                        "Ebs": {
                            "Encrypted": false,
                            "DeleteOnTermination": true,
                            "VolumeType": "gp2",
                            "VolumeSize": 8
                        }
                    }
                ],
                "EbsOptimized": false,
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ],
                "Monitoring": {
                    "Enabled": false
                },
                "InstanceType": "t3.nano",
                "AddressingType": "public",
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Description": "eth-zero",
                        "NetworkInterfaceId": "",
                        "DeleteOnTermination": true,
                        "SubnetId": "subnet-420ffc2b",
                        "AssociatePublicIpAddress": true
                    }
                ]
            },
            "Type": "one-time",
            "CreateTime": "2019-02-24T15:37:26.000Z",
            "SpotPrice": "0.008000"
        },
        {
            "Status": {
                "Message": "Your Spot request failed due to bad parameters.",
                "Code": "bad-parameters",
                "UpdateTime": "2019-02-24T14:33:43.000Z"
            },
            "ActualBlockHourlyPrice": "0.002000",
            "ValidUntil": "2019-03-03T14:33:42.000Z",
            "InstanceInterruptionBehavior": "terminate",
            "Tags": [],
            "Fault": {
                "Message": "Invalid device name /dev/sda",
                "Code": "InvalidBlockDeviceMapping"
            },
            "BlockDurationMinutes": 60,
            "SpotInstanceRequestId": "sir-n7c15y5p",
            "State": "cancelled",
            "ProductDescription": "Linux/UNIX",
            "LaunchedAvailabilityZone": "eu-north-1a",
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default",
                    "AvailabilityZone": "eu-north-1a"
                },
                "ImageId": "ami-6d27a913",
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda",
                        "VirtualName": "root",
                        "NoDevice": "",
                        "Ebs": {
                            "Encrypted": false,
                            "DeleteOnTermination": true,
                            "VolumeType": "gp2",
                            "VolumeSize": 8
                        }
                    }
                ],
                "EbsOptimized": false,
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ],
                "Monitoring": {
                    "Enabled": false
                },
                "InstanceType": "t3.nano",
                "AddressingType": "public",
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Description": "eth-zero",
                        "NetworkInterfaceId": "",
                        "DeleteOnTermination": true,
                        "SubnetId": "subnet-420ffc2b",
                        "AssociatePublicIpAddress": true
                    }
                ]
            },
            "Type": "one-time",
            "CreateTime": "2019-02-24T14:33:42.000Z",
            "SpotPrice": "0.011600"
        }
    ]
}


답변

값에 공백이없는 경우 다음이 도움이 될 수 있습니다.

read -r -a data <<<'name1 value1 name2 value2'

echo "name value"
echo "=========="

for ((i=0; i<${#data[@]}; i+=2)); do
  echo ${data[$i]} ${data[$((i+1))]}
done

산출

name value
==========
name1 value1
name2 value2


답변

위 답변의 문제는 필드가 모두 동일한 너비 인 경우에만 작동한다는 것입니다.

이 문제를 방지하기 위해 Linux column명령을 사용할 수 있습니다.

// input.json
[
  {
    "name": "George",
    "id": "a very very long field",
    "email": "george@domain.com"
  },
  {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
  },
  {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
  }
]

그때:

▶ jq -r '.[] | [.id, .name] | @tsv' input.json | column -ts $'\t'
a very very long field  George
18                      Jack
19                      Joe


답변