awk / sed / perl one liner + cara mencetak hanya baris properti dari file json

10

cara mencetak hanya garis-garis properti dari file json

contoh file 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"
      }
    }
  ]

output yang diharapkan

    "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"
yael
sumber
3
Pertanyaan terkait pada SO: Parsing JSON dengan alat Unix
hoefling

Jawaban:

33

Jq adalah alat yang tepat untuk memproses data JSON:

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

Hasil:

"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"

Jika benar-benar wajib untuk mendapatkan setiap kunci dan nilai yang dikutip ganda - gunakan modifikasi berikut:

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

Hasil:

"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",
RomanPerekhrest
sumber
Anda menganjurkan menggunakan alat sintaksis sadar ( jq) daripada operasi string naif, yang bagus, tetapi kemudian Anda menggunakan operasi string naif untuk melakukan (terbatas) proses urutan melarikan diri untuk output. Bagi saya itu bukan ide yang bagus. jqharus memiliki cara untuk keluar dari nilai output dengan benar, bukan?
Daniel Pryden
@DanielPryden, Tidak. Meskipun jqmemiliki beberapa cara untuk keluar dari nilai output (seperti @text, @shdll) dengan benar, itu tidak akan membantu dalam kasus khusus ini.
RomanPerekhrest
Varian yang meninggalkan nilai properti sebagai objek JSON dan menggunakan sed untuk menghapus kawat gigi dan ruang kosong yang tidak diinginkan:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet
mengapa "," tidak muncul di output, seperti hasil yang saya harapkan?
yael
dapatkah Anda melihat "hasil yang saya harapkan", dapatkah Anda mengedit jawaban Anda sesuai dengan hasil yang saya harapkan?
yael
27

Tolong, tolong jangan membiasakan parsing data terstruktur dengan alat tidak terstruktur. Jika Anda mem-parsing XML, JSON, YAML dll., Gunakan parser tertentu, setidaknya untuk mengubah data terstruktur menjadi bentuk yang lebih tepat untuk AWK sed,, grepdll.

Dalam hal ini, gronakan sangat membantu:

$ 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";

(Anda dapat memposting proses ini dengan | cut -d. -f4- | gron --ungronuntuk mendapatkan sesuatu yang sangat dekat dengan output yang Anda inginkan, meskipun masih sebagai JSON yang valid.)

jqadalah juga tepat .

Stephen Kitt
sumber
2

From Sed - An Introduction and Tutorial oleh Bruce Barnett :

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

Untuk pencocokan yang lebih tepat dan juga mengurus penutupan garis braket dengan spasi kosong yang dapat Anda gunakan

sed -E -n '/"properties" : {/,/^[[:blank:]]*}[[:blank:]]$/ {
               /"properties" : {/n
               /^[[:blank:]]*}[[:blank:]]$/ !p
           }' FILE.json
nohillside
sumber
Saya tidak terbiasa dengan JSON tapi mungkin /}/lebih aman daripada /}$. Yang terakhir tampaknya tidak memiliki kelebihan apa pun.
Hauke ​​Laging
1
@ HaukeLaging Tanpa penanda garis akhir sudah cocok dengan contentgaris yang berisi suatu }tempat.
nohillside
5
Meskipun mungkin, kemungkinan besar hanya akan berfungsi pada file contoh . Jika Anda ingin mengurai data terstruktur, Anda sebaiknya menggunakan sesuatu yang dirancang untuk itu. Baik itu jq, xpath, yq, xq, dll. Itu karena menguraikannya dengan alat yang berorientasi garis pada akhirnya akan menggigit Anda di belakang dan men-debug yang mungkin tidak mudah.
nert
Misalnya, apa yang terjadi jika salah satu bidang 'href' berisi kata "properti"?
Stig Hemmer
1
@ StigHemmer Itu sebabnya saya memperluas pola pada contoh kedua. Tetapi saya sepenuhnya setuju bahwa menggunakan gronatau jqmerupakan pendekatan yang lebih baik.
nohillside
2

sedsatu liner. Mencetak garis antara ekspresi reguler properties(yaitu garis yang berisi "properti") dan ekspresi reguler ^ *}(yaitu garis yang dimulai dengan nol atau lebih banyak spasi diikuti oleh "}" dan akhir baris).

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

awk satu liner.

awk '/^ *}/{s=0}/properties/{getline;s=1}s' file.json
steve
sumber
mungkin Anda bisa menjelaskan cara kerja pencocokan pola Anda.
vfbsilva
1
Meskipun ini berfungsi untuk file contoh yang diberikan, berisiko mencoba mengurai JSON dengan alat yang tidak memahaminya. Misalnya, apa yang terjadi jika salah satu bidang 'href' berisi kata "properti"? Itu jauh lebih sedikit rawan bug ke alat yang sadar JSON seperti jawaban terpilih.
Stig Hemmer
3
Setuju, berisiko. Tetapi OP secara khusus menginginkan solusi satu-liner menggunakan sed / awk / perl. Jawaban yang saya berikan memenuhi semua kriteria ini.
steve
Apa //!partinya Cetak kalau bukan salah satu hal yang cocok?
David Conrad
1
Ah, mengerti, //mengulangi regex terakhir, !bukan, pcetak. Bagus.
David Conrad
1

Ini ditandai perl, dan saya belum melihat perljawaban, jadi saya akan masukkan.

Jangan gunakan ekspresi reguler atau parser 'tidak terstruktur' lainnya. perlmemiliki JSONmodul dengannya. ( JSON::PPAdalah bagian dari inti sejak 5.14 juga)

#!/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"
      }
    }
  ]
}

Secara alami Anda akan membaca dari STDINatau nama file daripada DATAdalam skenario penggunaan nyata Anda.

Sobrique
sumber