awk / sed / perl one liner + jsonファイルからプロパティ行のみを印刷する方法


10

jsonファイルからプロパティ行のみを印刷する方法

jsonファイルの例

{
  "href" : "http://master02:8080/api/v1/clusters/HDP/configurations?type=kafka-env&tag=version1527250007610",
  "items" : [
    {
      "href" : "http://master02:8080/api/v1/clusters/HDP/configurations?type=kafka-env&tag=version1527250007610",
      "tag" : "version1527250007610",
      "type" : "kafka-env",
      "version" : 8,
      "Config" : {
        "cluster_name" : "HDP",
        "stack_id" : "HDP-2.6"
      },
      "properties" : {
        "content" : "\n#!/bin/bash\n\n# Set KAFKA specific environment variables here.\n\n# The java implementation to use.\nexport JAVA_HOME={{java64_home}}\nexport PATH=$PATH:$JAVA_HOME/bin\nexport PID_DIR={{kafka_pid_dir}}\nexport LOG_DIR={{kafka_log_dir}}\nexport KAFKA_KERBEROS_PARAMS={{kafka_kerberos_params}}\nexport JMX_PORT=9997\n# Add kafka sink to classpath and related depenencies\nif [ -e \"/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\" ]; then\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/lib/*\nfi\n\nif [ -f /etc/kafka/conf/kafka-ranger-env.sh ]; then\n. /etc/kafka/conf/kafka-ranger-env.sh\nfi",
        "is_supported_kafka_ranger" : "true",
        "kafka_log_dir" : "/var/log/kafka",
        "kafka_pid_dir" : "/var/run/kafka",
        "kafka_user" : "kafka",
        "kafka_user_nofile_limit" : "128000",
        "kafka_user_nproc_limit" : "65536"
      }
    }
  ]

期待される出力

    "content" : "\n#!/bin/bash\n\n# Set KAFKA specific environment variables here.\n\n# The java implementation to use.\nexport JAVA_HOME={{java64_home}}\nexport PATH=$PATH:$JAVA_HOME/bin\nexport PID_DIR={{kafka_pid_dir}}\nexport LOG_DIR={{kafka_log_dir}}\nexport KAFKA_KERBEROS_PARAMS={{kafka_kerberos_params}}\nexport JMX_PORT=9997\n# Add kafka sink to classpath and related depenencies\nif [ -e \"/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\" ]; then\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/lib/*\nfi\n\nif [ -f /etc/kafka/conf/kafka-ranger-env.sh ]; then\n. /etc/kafka/conf/kafka-ranger-env.sh\nfi",
    "is_supported_kafka_ranger" : "true",
    "kafka_log_dir" : "/var/log/kafka",
    "kafka_pid_dir" : "/var/run/kafka",
    "kafka_user" : "kafka",
    "kafka_user_nofile_limit" : "128000",
    "kafka_user_nproc_limit" : "65536"

3
SOに関する関連質問:Unixツールを使用したJSONの解析
18年

回答:


33

Jq JSONデータを処理するための適切なツールです。

jq '.items[].properties | to_entries[] | "\(.key) : \(.value)"' input.json

出力:

"content : \n#!/bin/bash\n\n# Set KAFKA specific environment variables here.\n\n# The java implementation to use.\nexport JAVA_HOME={{java64_home}}\nexport PATH=$PATH:$JAVA_HOME/bin\nexport PID_DIR={{kafka_pid_dir}}\nexport LOG_DIR={{kafka_log_dir}}\nexport KAFKA_KERBEROS_PARAMS={{kafka_kerberos_params}}\nexport JMX_PORT=9997\n# Add kafka sink to classpath and related depenencies\nif [ -e \"/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\" ]; then\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/lib/*\nfi\n\nif [ -f /etc/kafka/conf/kafka-ranger-env.sh ]; then\n. /etc/kafka/conf/kafka-ranger-env.sh\nfi"
"is_supported_kafka_ranger : true"
"kafka_log_dir : /var/log/kafka"
"kafka_pid_dir : /var/run/kafka"
"kafka_user : kafka"
"kafka_user_nofile_limit : 128000"
"kafka_user_nproc_limit : 65536"

二重引用符で囲まれた各キーと値を取得することが本当に必須の場合は、次の変更を使用します。

jq -r '.items[].properties | to_entries[]
       | "\"\(.key)\" : \"\(.value | gsub("\n";"\\n"))\","' input.json

出力:

"content" : "\n#!/bin/bash\n\n# Set KAFKA specific environment variables here.\n\n# The java implementation to use.\nexport JAVA_HOME={{java64_home}}\nexport PATH=$PATH:$JAVA_HOME/bin\nexport PID_DIR={{kafka_pid_dir}}\nexport LOG_DIR={{kafka_log_dir}}\nexport KAFKA_KERBEROS_PARAMS={{kafka_kerberos_params}}\nexport JMX_PORT=9997\n# Add kafka sink to classpath and related depenencies\nif [ -e "/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar" ]; then\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/lib/*\nfi\n\nif [ -f /etc/kafka/conf/kafka-ranger-env.sh ]; then\n. /etc/kafka/conf/kafka-ranger-env.sh\nfi",
"is_supported_kafka_ranger" : "true",
"kafka_log_dir" : "/var/log/kafka",
"kafka_pid_dir" : "/var/run/kafka",
"kafka_user" : "kafka",
"kafka_user_nofile_limit" : "128000",
"kafka_user_nproc_limit" : "65536",

jqナイーブ文字列操作ではなく構文対応ツール()を使用することを推奨しますが、ナイーブ文字列操作を使用して(制限付き)出力のエスケープシーケンス処理を行います。それは私には良い考えのようには思えません。jq出力の値を適切にエスケープする方法が必要ですよね?
Daniel Pryden

@DanielPryden号ががjq正しく出力の値をエスケープするいくつかの方法持っている(のような@text@shなど)、それらは、この特定のケースではないのに役立ちます。
RomanPerekhrest

プロパティ値をJSONオブジェクトとして残し、sedを使用して不要な中括弧と空白を削除するバリアント:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet

期待どおりの結果として、「、」が出力に表示されないのはなぜですか?
yael

私の「期待される出力」をご覧ください。私の期待される結果に従って回答を編集できますか?
yael 2018年

27

非構造化ツールで構造化データを解析する習慣をつけないでください。あなたがXML、JSON、YAMLなどを解析している場合は、AWKのためのより適切な形、に構造化されたデータを変換するために、少なくとも、特定のパーサを使用sedgrepなど

この場合、gron非常に役立ちます:

$ gron yourfile | grep -F .properties.
json.items[0].properties.content = "\n#!/bin/bash\n\n# Set KAFKA specific environment variables here.\n\n# The java implementation to use.\nexport JAVA_HOME={{java64_home}}\nexport PATH=/usr/lib/ccache:/home/steve/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/bin\nexport PID_DIR={{kafka_pid_dir}}\nexport LOG_DIR={{kafka_log_dir}}\nexport KAFKA_KERBEROS_PARAMS={{kafka_kerberos_params}}\nexport JMX_PORT=9997\n# Add kafka sink to classpath and related depenencies\nif [ -e \"/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\" ]; then\n  export CLASSPATH=:/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\n  export CLASSPATH=:/usr/lib/ambari-metrics-kafka-sink/lib/*\nfi\n\nif [ -f /etc/kafka/conf/kafka-ranger-env.sh ]; then\n. /etc/kafka/conf/kafka-ranger-env.sh\nfi";
json.items[0].properties.is_supported_kafka_ranger = "true";
json.items[0].properties.kafka_log_dir = "/var/log/kafka";
json.items[0].properties.kafka_pid_dir = "/var/run/kafka";
json.items[0].properties.kafka_user = "kafka";
json.items[0].properties.kafka_user_nofile_limit = "128000";
json.items[0].properties.kafka_user_nproc_limit = "65536";

| cut -d. -f4- | gron --ungron有効なJSONでありながら、これを後処理して目的の出力に非常に近いものを取得できます。)

jqであるにも適切


2

セッドから-ブルース・バーネットによる紹介とチュートリアル

sed -n '/properties/,/}$/ {
            /properties/n
            /}$/ !p
        }' FILE.json

より正確に一致させるため、および追加の空白を使用して括弧線を閉じる場合にも使用できます

sed -E -n '/"properties" : {/,/^[[:blank:]]*}[[:blank:]]$/ {
               /"properties" : {/n
               /^[[:blank:]]*}[[:blank:]]$/ !p
           }' FILE.json

私はJSONに精通していません/}/が、おそらくそれよりも安全です/}$。後者はとにかく何の利点もないようです。
Hauke Laging

1
@HaukeLaging行末マーカーがない場合contentは、}どこかを含む行と既に一致しています。
-nohillside、

5
それは可能ですが、ほとんどの場合サンプルファイルでのみ機能します。構造化データを解析する場合は、そのために設計されたものを使用する必要があります。それがjq、xpath、yq、xqなどであることを確認してください。これは、ライン指向のツールで解析すると、最終的には奥の方に食い込み、デバッグが非常に簡単にならない可能性があるためです。
18年

たとえば、「href」フィールドの1つに「プロパティ」という単語が含まれている場合はどうなりますか?
Stig Hemmer、2018年

1
@StigHemmerそのため、2番目の例でパターンを拡張しました。しかし、私は、gronまたはjqより優れたアプローチを使用することに完全に同意します。
-nohillside、

2

sed一発ギャグ。正規表現properties(つまり、「プロパティ」を含む行)と正規表現^ *}(つまり、0個以上のスペースで始まり、「}」と行末)の間の行を出力します。

sed -n '/properties/,/^ *}$/{//!p}' file.json

awk 一発ギャグ。

awk '/^ *}/{s=0}/properties/{getline;s=1}s' file.json

多分あなたはあなたのパターンマッチングがどのように機能するかを説明することができます。
vfbsilva 2018年

1
これは与えられた例のファイルで機能しますが、それを理解しないツールでJSONを解析しようとすると危険です。たとえば、「href」フィールドの1つに「プロパティ」という単語が含まれている場合はどうなりますか?上位投票の回答のように、JSON対応のツールにバグが発生する可能性ははるかに低くなります。
Stig Hemmer、2018年

3
同意します、危険です。しかし、OPは特にsed / awk / perlを使用したワンライナーソリューションを望んでいました。私が与えた答えはこれらすべての基準を満たしています。
スティーブ

どういう//!p意味ですか?一致するものでない場合は印刷しますか?
デビッドコンラッド

1
ああ、//わかった。印刷で!はなく、最後の正規表現を繰り返すp。ナイス。
デビッドコンラッド

1

タグが付けられていてperlperlまだ回答が見つからないため、チップインします。

正規表現や他の「非構造化」パーサーを使用しないでください。それにモジュールperlがありJSONます。(JSON::PP5.14以降もコアの一部です)

#!/usr/bin/env perl

use strict;
use warnings;
use JSON;
use Data::Dumper;

my $str = do { local $/; <DATA> };

my $json = decode_json ( $str );

my $properties = $json -> {items} -> [0] -> {properties}; 

#dump the whole lot:
print Dumper $properties;


# or iterate
foreach my $key ( sort keys %$properties ) { 
   print "$key => ", $properties -> {$key},"\n";
}


__DATA__
{
  "href" : "http://master02:8080/api/v1/clusters/HDP/configurations?type=kafka-env&tag=version1527250007610",
  "items" : [
    {
      "href" : "http://master02:8080/api/v1/clusters/HDP/configurations?type=kafka-env&tag=version1527250007610",
      "tag" : "version1527250007610",
      "type" : "kafka-env",
      "version" : 8,
      "Config" : {
        "cluster_name" : "HDP",
        "stack_id" : "HDP-2.6"
      },
      "properties" : {
        "content" : "\n#!/bin/bash\n\n# Set KAFKA specific environment variables here.\n\n# The java implementation to use.\nexport JAVA_HOME={{java64_home}}\nexport PATH=$PATH:$JAVA_HOME/bin\nexport PID_DIR={{kafka_pid_dir}}\nexport LOG_DIR={{kafka_log_dir}}\nexport KAFKA_KERBEROS_PARAMS={{kafka_kerberos_params}}\nexport JMX_PORT=9997\n# Add kafka sink to classpath and related depenencies\nif [ -e \"/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\" ]; then\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/ambari-metrics-kafka-sink.jar\n  export CLASSPATH=$CLASSPATH:/usr/lib/ambari-metrics-kafka-sink/lib/*\nfi\n\nif [ -f /etc/kafka/conf/kafka-ranger-env.sh ]; then\n. /etc/kafka/conf/kafka-ranger-env.sh\nfi",
        "is_supported_kafka_ranger" : "true",
        "kafka_log_dir" : "/var/log/kafka",
        "kafka_pid_dir" : "/var/run/kafka",
        "kafka_user" : "kafka",
        "kafka_user_nofile_limit" : "128000",
        "kafka_user_nproc_limit" : "65536"
      }
    }
  ]
}

当然、実際の使用シナリオでSTDINはなく、ファイル名またはファイル名を読み取りDATAます。

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