Linuxでいくつかのパラメーターを抽出する必要があるJSON出力があります。
これはJSON出力です:
{
"OwnerId": "121456789127",
"ReservationId": "r-48465168",
"Groups": [],
"Instances": [
{
"Monitoring": {
"State": "disabled"
},
"PublicDnsName": null,
"RootDeviceType": "ebs",
"State": {
"Code": 16,
"Name": "running"
},
"EbsOptimized": false,
"LaunchTime": "2014-03-19T09:16:56.000Z",
"PrivateIpAddress": "10.250.171.248",
"ProductCodes": [
{
"ProductCodeId": "aacglxeowvn5hy8sznltowyqe",
"ProductCodeType": "marketplace"
}
],
"VpcId": "vpc-86bab0e4",
"StateTransitionReason": null,
"InstanceId": "i-1234576",
"ImageId": "AMI-b7f6c5de",
"PrivateDnsName": "ip-10-120-134-248.ec2.internal",
"KeyName": "Test_Virginia",
"SecurityGroups": [
{
"GroupName": "Test",
"GroupId": "sg-12345b"
}
],
"ClientToken": "VYeFw1395220615808",
"SubnetId": "subnet-12345314",
"InstanceType": "t1.micro",
"NetworkInterfaces": [
{
"Status": "in-use",
"SourceDestCheck": true,
"VpcId": "vpc-123456e4",
"Description": "Primary network interface",
"NetworkInterfaceId": "eni-3619f31d",
"PrivateIpAddresses": [
{
"Primary": true,
"PrivateIpAddress": "10.120.134.248"
}
],
"Attachment": {
"Status": "attached",
"DeviceIndex": 0,
"DeleteOnTermination": true,
"AttachmentId": "eni-attach-9210dee8",
"AttachTime": "2014-03-19T09:16:56.000Z"
},
"Groups": [
{
"GroupName": "Test",
"GroupId": "sg-123456cb"
}
],
"SubnetId": "subnet-31236514",
"OwnerId": "109030037527",
"PrivateIpAddress": "10.120.134.248"
}
],
"SourceDestCheck": true,
"Placement": {
"Tenancy": "default",
"GroupName": null,
"AvailabilityZone": "us-east-1c"
},
"Hypervisor": "xen",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": false,
"VolumeId": "vol-37ff097b",
"AttachTime": "2014-03-19T09:17:00.000Z"
}
}
],
"Architecture": "x86_64",
"KernelId": "aki-88aa75e1",
"RootDeviceName": "/dev/sda1",
"VirtualizationType": "paravirtual",
"Tags": [
{
"Value": "Server for testing RDS feature in us-east-1c AZ",
"Key": "Description"
},
{
"Value": "RDS_Machine (us-east-1c)",
"Key": "Name"
},
{
"Value": "1234",
"Key": "cost.centre",
},
{
"Value": "Jyoti Bhanot",
"Key": "Owner",
}
],
"AmiLaunchIndex": 0
}
]
}
インスタンスIDなどの見出し、名前などのタグ、コストセンター、所有者を含むファイルを書きたいのですが。 JSON出力の特定の値以下。ここに示す出力は単なる例です。
sed
とawk
を使用してどうすればよいですか?
予想される出力:
Instance id Name cost centre Owner
i-1234576 RDS_Machine (us-east-1c) 1234 Jyoti
ほぼすべてのプログラミング言語でパーサーを使用できることは、データ交換形式としてのJSONの利点の1つです。
JSONパーサーを実装するのではなく、 jq などのJSON解析用に構築されたツールか、JSONライブラリを備えた汎用スクリプト言語のいずれかを使用するほうがよいでしょう。
たとえば、jqを使用して、次のようにInstances配列の最初の項目からImageIDを取得できます。
jq '.Instances[0].ImageId' test.json
または、RubyのJSONライブラリを使用して同じ情報を取得するには:
Ruby -rjson -e 'j = JSON.parse(File.read("test.json")); puts j["Instances"][0]["ImageId"]'
修正された質問やコメントのすべてに回答するわけではありませんが、以下の説明で開始できます。
STDINからaを読み取り、出力例の2行目を出力できるRubyスクリプトがあるとします。このスクリプトは次のようになります。
#!/usr/bin/env Ruby
require 'json'
data = JSON.parse(ARGF.read)
instance_id = data["Instances"][0]["InstanceId"]
name = data["Instances"][0]["Tags"].find {|t| t["Key"] == "Name" }["Value"]
owner = data["Instances"][0]["Tags"].find {|t| t["Key"] == "Owner" }["Value"]
cost_center = data["Instances"][0]["SubnetId"].split("-")[1][0..3]
puts "#{instance_id}\t#{name}\t#{cost_center}\t#{owner}"
このようなスクリプトを使用して、全体の目標を達成するにはどうすればよいでしょうか。さて、あなたはすでに次のものを持っていると仮定します:
1つの方法は、シェルを使用してこれらのツールを組み合わせることです。
echo -e "Instance id\tName\tcost centre\tOwner"
for instance in $(list-instances); do
get-json-for-instance $instance | ./ugly-Ruby-scriptrb
done
さて、おそらく「Instances」配列にさらに項目があるすべてのインスタンスに対して1つのjson blobを与える単一のコマンドがあるかもしれません。そうだとすれば、単純に最初の項目を使用するのではなく、スクリプトを少し変更して配列を反復処理する必要があるだけです。
結局、この問題を解決する方法は、Unixの多くの問題を解決する方法です。それをより簡単な問題に分解します。簡単な問題を解決するためのツールを見つけたり、作成したりします。これらのツールをシェルまたは他のオペレーティングシステムの機能と組み合わせます。
[0]あなたがどこからコストセンターを得るか私にはわからないことに注意してください、それで私はそれを作りました。
次のpythonスクリプトを使用して、そのデータを解析できます。array1.json
、array2.json
などのファイル内の配列からのJSONデータがあると仮定しましょう。
import json
import sys
from pprint import pprint
jdata = open(sys.argv[1])
data = json.load(jdata)
print "InstanceId", " - ", "Name", " - ", "Owner"
print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"]
jdata.close()
そして、ただ実行します:
$ for x in `ls *.json`; do python parse.py $x; done
InstanceId - Name - Owner
i-1234576 - RDS_Machine (us-east-1c) - Jyoti Bhanot
私はあなたのデータにコストを見たことがありません、それが私がそれを含めなかった理由です。
コメントでの議論によると、私はparse.pyスクリプトを更新しました:
import json
import sys
from pprint import pprint
jdata = sys.stdin.read()
data = json.loads(jdata)
print "InstanceId", " - ", "Name", " - ", "Owner"
print data["Instances"][0]["InstanceId"], " - " ,data["Instances"][0]["Tags"][1]["Value"], " - " ,data["Instances"][0]["Tags"][2]["Value"]
次のコマンドを実行してみてください:
#ec2-describe-instance <instance> | python parse.py
他の人がjsonを解析する良い方法を示す質問に対する一般的な回答を提供しましたが、私と同じように、他のパッケージに依存せずにawkやsedなどのコアツールを使用してawsインスタンスIDを抽出する方法を探していました。これを行うには、awkコマンドに「--output = text」引数を渡して、awkで解析可能な文字列を取得できます。これで、次のようなものを使用してインスタンスIDを取得できます...
aws ec2 run-instances --output text | awk -F"\t" '$1=="INSTANCES" {print $8}'
次のjqコード:
.Instances[] | (.Tags | map(.value=.Value | .key=.Key) | from_entries) as $tags | "\(.InstanceId) | \($tags.Name) | \($tags["cost.centre"]) | \($tags.Owner)"
次のように使用されます:
json_producer | jq -r '<jq code...>'
出力:
i-1234576 | RDS_Machine (us-east-1c) | 1234 | Jyoti Bhanot
コードを理解するためのいくつかのポインタ:
from_entries
は、{key:a, value:b}
のようなオブジェクトの配列を取り、対応するキー/値のペア({a: b}
)を持つオブジェクトに変換します。Key
配列のValue
およびTags
キーは小文字に変換する必要がありました。詳細については、jqのチュートリアルとマニュアルを https://stedolan.github.io/jq/ で参照してください。
Jshon はいくつかのディストリビューションで利用可能です:
$ echo your_JSON|jshon -e Instances -a -e InstanceId -u -p -e Tags -a -e Key -u -p -e Value -u
i-1234576
Description
Server for testing RDS feature in us-east-1c AZ
Name
RDS_Machine (us-east-1c)
cost.centre
1234
Owner
Jyoti Bhanot
悪い説明:-e uu
はオブジェクトuu
を抽出し、-a
は配列を使用可能にします(これを正しくフレーズしたかどうかはわかりませんが...)、-u
は文字列をデコードします、-p
は前のアイテムに戻ります(-i N
、Nは任意の数、同じ効果があるようです)。
ケースによっては、出力にいくつかの後処理が必要な場合があります(ご覧のように)。
Jshon
は、JSONの奇形に対して堅牢に見えます(閉じ中かっこの前にコンマを含む "タグ"を使用するとエラーが発生します)。
誰かが別のスレッドで jsawk について言及しましたが、テストしていません。
これが上記のAWSユースケースに限定されている場合は、CLI API呼び出しに--queryおよび--outputフラグを使用する必要があります
http://docs.aws.Amazon.com/cli/latest/userguide/controlling-output.html
ここにワンライナーの提案があります:
pr -mt \
<(grep -o ".*: .*," in.json | grep -iw InstanceId | cut -d: -f2) \
<(grep -o ".*: .*," in.json | grep -iw Value | cut -d: -f2) \
<(grep -o ".*: .*," in.json | grep -iw Key | cut -d: -f2)
完璧ではありませんが、少し調整すればうまくいきます。
基本的にpr
を使用して、各セットの結果を列ごとに出力します。各結果セットは、JSONファイルを解析してキーに基づいて値を返すプロセス置換によって返されます。
これは、 指定されたKey-Valueの内容と同様に機能します。キーで値をグループ化し、値でソートするにはどうすればよいですか?
jtc
cliツールを見てください:
jsonから必要な情報を簡単に抽出できます(file.json
、ところで、JSONを修正する必要があります。追加のコンマがいくつかあります):
bash $ cat file.json | jtc -x '<InstanceId>l+0[-1]' -y '[InstanceId]' -y "[Key]:<Name>[-1][Value]" -y "[Key]:<cost.centre>[-1][Value]" -y "[Key]:<Owner>[-1][Value]" | sed 's/"/\\"/g' | xargs -L4 echo
"i-1234576" "RDS_Machine (us-east-1c)" "1234" "Jyoti Bhanot"
bash $