Linuxでシェルスクリプトを使用してJSONを解析する方法は?


56

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出力の特定の値以下。ここに示した出力は単なる例です。

sedand を使用してどのようにできawkますか?

期待される出力:

 Instance id         Name                           cost centre             Owner
    i-1234576          RDS_Machine (us-east-1c)        1234                   Jyoti

1
CLI呼び出しをPythonにパイプします。これはEC2インスタンスにネイティブであるため推奨されます。PythonはJSONを簡単に解釈できます。例については、以下の回答を参照してください。もちろん、他のSS言語も使用できますが、Pythonが既に存在するのに、インストールが必要になります。
ロビーアヴェリル14年

回答:


65

ほぼすべてのプログラミング言語でパーサーを使用できることは、データ交換形式としての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からを読み取り、サンプルoutput [0]の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}"

このようなスクリプトを使用して、目標全体をどのように達成できますか?さて、あなたはすでに次のものを持っていると仮定します:

  • すべてのインスタンスをリストするコマンド
  • リスト上の任意のインスタンスについて上記のjsonを取得し、STDOUに出力するコマンド

1つの方法は、シェルを使用してこれらのツールを結合することです。

echo -e "Instance id\tName\tcost centre\tOwner"
for instance in $(list-instances); do
    get-json-for-instance $instance | ./ugly-ruby-scriptrb
done

これで、「インスタンス」配列内のより多くの項目を持つすべてのインスタンスに対して1つのjson blobを提供する単一のコマンドを使用できます。その場合、最初の項目を使用するだけでなく、配列を反復処理するためにスクリプトを少し変更するだけで済みます。

最後に、この問題を解決する方法は、Unixの多くの問題を解決する方法です。簡単な問題に分けてください。より簡単な問題を解決するためのツールを見つけるか作成します。これらのツールをシェルまたは他のオペレーティングシステム機能と組み合わせます。

[0]コストセンターがどこから得られるのかわからないことに注意してください。


私は自分のマシンにjqをインストールしました。しかし、私は情報を取得する方法を知りません。私は疑問に更新しています
user3086014

どうやってするか。コマンドec2-describe instanceは、このようなreslutを提供します。これは1インスタンスのデータであり、100インスタンスがあります。スクリプトでそれを行う方法
user3086014

私は私に出力を与えるAWS CLIツールを持っています。今、私が本当に知らない出力と必要なタグを解析する方法
user3086014 14年

2
@ user3086014申し訳ありませんが、この回答にこれ以上の作業を加えることはありません。私が持っているRubyの例を見てください。必要なJSONのさまざまな部分からタグを取得する方法を開始するのに適した場所を提供する必要があります。
スティーブンD 14年

利用可能なjsonツールのmoltitudeでは、jqは私のお気に入りのstedolan.github.io/jq/manualです。stdディストリビューションでも利用できます。フィルターをテストするためのプレイグラウンドは、jqplay.org
jq?

15

次のpythonスクリプトを使用して、そのデータを解析できます。あなたのようなファイル内の配列からJSONデータを持っていることを前提としていますarray1.jsonarray2.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

ただし、これは1つの配列であり、コマンドによって返される類似の配列があります。ことを行う方法
user3086014

このデータは、実行時にec2-describeインスタンスコマンドによって生成されます。それを処理する方法
user3086014

私はこのPythonスクリプトを少し変更しました: import json from pprint import pprint jdata = open('example.json') 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() array1.json、array2.jsonなどのファイルに配列からすべてのjsonデータがある場合、次のように実行できます: # for x in ls * .json; do python parse.py $x; done
Robertジョンツィー14年

回答自体を更新できます。その読めません
user3086014

また、私はこのような配列のarrays.100持っている
user3086014

9

次の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})を持つオブジェクトに変換します。
  • キー配列は、小文字に変換されなければなりませんでした。KeyValueTags
  • 最後の文字列はjqの文字列補間機能を使用します。必要に応じて調整できます。

詳細については、https: //stedolan.github.io/jq/でjqのチュートリアルとマニュアルを参照してください。


1
(.Tags | map({Value, Key}) | from_entries) as $tagsキーを小文字に変換せずに、を使用してタグの抽出を短縮できるようになりました。
mloughran

8

他の人はあなたの質問に一般的な回答を提供し、jsonを解析する良い方法を示していますが、私はあなたのように、他のパッケージに依存せずにawkやsedなどのコアツールを使用してawsインスタンスIDを抽出する方法を探していました。これを実現するために、awsコマンドに「--output = text」引数を渡して、awkの解析可能な文字列を渡すことができます。これにより、次のようなものを使用してインスタンスIDを取得できます...

aws ec2 run-instances --output text  | awk -F"\t" '$1=="INSTANCES" {print $8}'

3

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 NNは任意の数で、同じ効果があります) 。

ケースによっては、出力に後処理が必要になる場合があります(ご覧のように)。

Jshon ただし、JSONの不正に対しては堅牢であるように見えます(閉じ中括弧の前にコンマが含まれる「タグ」はエラーを発生させます)。

誰かが別のスレッドでjsawkに言及しましたが、テストしていません。



0

ワンライナーの提案は次のとおりです。

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ファイルを解析し、キーに基づいて値を返すプロセス置換によって返されます。

これは、「キー値コンテンツが指定されている場合、キーで値をグループ化し、値でソートするにはどうすればよいですか?」


0

jtcCLIツールをご覧ください。

file.jsonJSON から必要な情報を簡単に抽出できます(ただし 、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 $ 

-2

jq "." recovery.js | head -n 20

jasonファイルを次のような読みやすいものに変換します。

{
  "版": [
    「sessionrestore」、
    1
  ]、
  「windows」:[
    {
      「タブ」:[
        {
          「エントリ」:[
            {
              「url」:「http://orf.at/#/stories/2.../」、
              「タイトル」:「news.ORF.at」、
              「charset」:「UTF-8」、
              「ID」:9588、
              「docshellID」:298、
              「docIdentifier」:10062、
              「持続」:true
            }、
...

これで、標準ツールを使用してデータを解析できるようになります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.