Ich habe gerade mit Bash Scripting angefangen und bin auf jq gestoßen, um mit JSON zu arbeiten.
Ich muss eine JSON-Zeichenfolge wie unten in eine Tabelle für die Ausgabe im Terminal umwandeln.
[{
"name": "George",
"id": 12,
"email": "[email protected]"
}, {
"name": "Jack",
"id": 18,
"email": "[email protected]"
}, {
"name": "Joe",
"id": 19,
"email": "[email protected]"
}]
Was ich im Terminal anzeigen möchte:
ID Name
=================
12 George
18 Jack
19 Joe
Beachten Sie, dass ich die E-Mail-Eigenschaft nicht für jede Zeile anzeigen möchte, daher sollte der Befehl jq eine Filterung beinhalten. Das Folgende gibt mir eine einfache Liste von Namen und IDs:
list=$(echo "$data" | jq -r '.[] | .name, .id')
printf "$list"
Das Problem dabei ist, dass ich es nicht wie eine Tabelle anzeigen kann. Ich weiß, dass jq einige Formatierungsoptionen hat, aber bei weitem nicht so gut wie die Optionen, die ich bei der Verwendung habe printf
. Ich denke, ich möchte diese Werte in einem Array erhalten, das ich dann selbst durchlaufen kann, um die Formatierung vorzunehmen ...? Die Dinge, die ich versucht habe, führen zu unterschiedlichen Ergebnissen, aber nie zu dem, was ich wirklich will.
Kann mich jemand in die richtige Richtung weisen?
jq -r ...
Befehls hinzufügen ?echo
kann vermieden werdenjq -r '...' <<<$data
oderjr -r '...' < input-file.json
."name1 value1 name2 value2 name3 value3"
wie kann ich sie als Tabelle drucken?Antworten:
Warum nicht so etwas wie:
echo '[{ "name": "George", "id": 12, "email": "[email protected]" }, { "name": "Jack", "id": 18, "email": "[email protected]" }, { "name": "Joe", "id": 19, "email": "[email protected]" }]' | jq -r '.[] | "\(.id)\t\(.name)"'
Ausgabe
Bearbeiten 1: Verwenden Sie für eine feinkörnige Formatierung Tools wie
awk
echo '[{ "name": "George", "id": 12, "email": "[email protected]" }, { "name": "Jack", "id": 18, "email": "[email protected]" }, { "name": "Joe", "id": 19, "email": "[email protected]" }]' | 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"
Edit 2: Als Antwort auf
Warum nicht?
Ein etwas kompliziertes Beispiel (tatsächlich von Ihrem geändert), in dem E-Mails in ein Array geändert werden, zeigt dies
echo '[{ "name": "George", "id": 20, "email": [ "[email protected]" , "[email protected]" ] }, { "name": "Jack", "id": 18, "email": [ "[email protected]" , "[email protected]" ] }, { "name": "Joe", "id": 19, "email": [ "[email protected]" ] }]' | jq -r '.[] | .email'
Ausgabe
[ "[email protected]", "[email protected]" ] [ "[email protected]", "[email protected]" ] [ "[email protected]" ]
quelle
awk
jedoch, dass komplizierte Fälle möglicherweise fehlschlagen. Für Ihren zweiten Kommentar sehen Sie sich die letzte Bearbeitung an und lesen Sie sie zusammen mit [dieser] Antwort.Die Verwendung des
@tsv
Filters ist sehr zu empfehlen, vor allem, weil er zahlreiche "Randfälle" auf standardmäßige Weise behandelt:Das Hinzufügen der Header kann folgendermaßen erfolgen:
jq -r '["ID","NAME"], ["--","------"], (.[] | [.id, .name]) | @tsv'
Das Ergebnis:
length*"-"
So automatisieren Sie die Erstellung der Strichlinie:
jq -r '(["ID","NAME"] | (., map(length*"-"))), (.[] | [.id, .name]) | @tsv'
quelle
Das manuelle Definieren von Headern ist nicht optimal! Das Weglassen von Headern ist ebenfalls nicht optimal.
TL; DR
Daten
[{ "name": "George", "id": 12, "email": "[email protected]" }, { "name": "Jack", "id": 18, "email": "[email protected]" }, { "name": "Joe", "id": 19, "email": "[email protected]" }]
Skript
wie man läuft
Ich habe diese Frage gefunden, als ich einige Daten von Amazon Web Services zusammengefasst habe. Das Problem, an dem ich gearbeitet habe, falls Sie ein anderes Beispiel wollen:
$ 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
Ausgabe:
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
Eingang:
$ 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" } ] }
quelle
column -t
machte den Trick, die Überschriften an der Tabelle selbst auszurichten. Vielen Dank!Wenn die Werte keine Leerzeichen enthalten, kann dies hilfreich sein:
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
Ausgabe
quelle