awk / sed / perl one liner + wie man nur die eigenschaftszeilen aus der json datei druckt

10

So drucken Sie nur die Eigenschaftszeilen aus der JSON-Datei

Beispiel einer JSON-Datei

{
  "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"
      }
    }
  ]

erwartete Ausgabe

    "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
quelle
3
Verwandte Frage zu SO: Parsen von JSON mit Unix-Tools
hoefling

Antworten:

33

Jq ist das richtige Werkzeug für die Verarbeitung von JSON-Daten:

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

Die Ausgabe:

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

Falls es wirklich obligatorisch ist, jeden Schlüssel und Wert in doppelte Anführungszeichen zu setzen, verwenden Sie die folgende Änderung:

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

Die Ausgabe:

"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
quelle
Sie empfehlen die Verwendung eines syntaxbewussten Tools ( jq) anstelle von naiven Zeichenfolgenoperationen, was gut ist, aber dann verwenden Sie eine naive Zeichenfolgenoperation, um die (eingeschränkte) Escape-Sequenzverarbeitung für die Ausgabe durchzuführen. Das scheint mir keine gute Idee zu sein. jqmuss eine Möglichkeit haben, dem Ausgabewert richtig zu entkommen, oder?
Daniel Pryden
@DanielPryden, Nr Obwohl jqeinige Möglichkeiten hat , um richtig den Wert für die Ausgabe zu entkommen (wie @text, @shusw.), werden diejenigen , die in diesem speziellen Fall keine Hilfe.
RomanPerekhrest
Eine Variante, die die Eigenschaftswerte als JSON-Objekte belässt und sed verwendet, um unerwünschte Klammern und Leerzeichen jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet
Warum wird "," nicht in der Ausgabe angezeigt, wie meine erwarteten Ergebnisse?
Yael
Kannst du bitte meine "erwartete Ausgabe" sehen, kannst du deine Antwort gemäß meinen erwarteten Ergebnissen bearbeiten?
Yael
26

Bitte, bitte gewöhnen Sie sich nicht an, strukturierte Daten mit unstrukturierten Tools zu analysieren. Wenn Sie XML sind Parsen, JSON, YAML usw., einen bestimmten Parser verwenden, zumindest die strukturierten Daten in eine geeignete Form für AWK zu konvertieren, sed, grepusw.

In diesem Fall gronwürde sehr helfen:

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

(Sie können dies nachbearbeiten | cut -d. -f4- | gron --ungron, um etwas zu erreichen, das Ihrer gewünschten Ausgabe sehr nahe kommt, wenn auch immer noch als gültiger JSON.)

jqist auch angemessen .

Stephen Kitt
quelle
2

Aus Sed - Eine Einführung und ein Tutorial von Bruce Barnett :

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

Für eine genauere Übereinstimmung und um auch das Schließen von Klammerlinien mit zusätzlichen Leerzeichen zu gewährleisten, können Sie diese verwenden

sed -E -n '/"properties" : {/,/^[[:blank:]]*}[[:blank:]]$/ {
               /"properties" : {/n
               /^[[:blank:]]*}[[:blank:]]$/ !p
           }' FILE.json
nohillside
quelle
Ich bin nicht mit JSON vertraut, aber vielleicht /}/ist es sicherer als /}$. Letzteres scheint ohnehin keine Vorteile zu haben.
Hauke ​​Laging
1
@HaukeLaging Ohne die Zeilenende-Markierung stimmt sie bereits mit der contentZeile überein , die }irgendwo ein enthält .
Nohillside
5
Obwohl dies möglich ist, funktioniert es höchstwahrscheinlich nur mit der Beispieldatei . Wenn Sie strukturierte Daten analysieren möchten, sollten Sie lieber etwas verwenden, das dafür entwickelt wurde. Sei es jq, xpath, yq, xq usw. Das liegt daran, dass das Parsen mit zeilenorientierten Tools Sie irgendwann in den Rücken beißen und das Debuggen möglicherweise nicht sehr einfach ist.
nert
Was passiert zum Beispiel, wenn eines der 'href'-Felder das Wort "Eigenschaften" enthält?
Stig Hemmer
1
@StigHemmer Deshalb habe ich das Muster im zweiten Beispiel erweitert. Aber ich stimme vollkommen zu, dass die Verwendung von gronoder jqder bessere Ansatz ist.
Nohillside
2

sedEinzeiler. Drucken Sie Zeilen zwischen regulären Ausdrücken properties(dh Zeilen mit "Eigenschaften") und regulären Ausdrücken ^ *}(dh Zeilen, die mit null oder mehr Leerzeichen beginnen, gefolgt von "}" und Zeilenende).

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

awk Einzeiler.

awk '/^ *}/{s=0}/properties/{getline;s=1}s' file.json
Steve
quelle
Vielleicht könnten Sie erklären, wie Ihr Pattern Matching funktioniert.
vfbsilva
1
Während dies für die angegebene Beispieldatei funktioniert, ist es riskant, JSON mit Tools zu analysieren, die es nicht verstehen. Was passiert zum Beispiel, wenn eines der 'href'-Felder das Wort "Eigenschaften" enthält? Es ist weit weniger fehleranfällig für ein JSON-fähiges Tool wie die am besten bewerteten Antworten.
Stig Hemmer
3
Stimme zu, riskant. OP wollte jedoch speziell eine Einzeilerlösung mit sed / awk / perl. Die Antwort, die ich gegeben habe, erfüllt alle diese Kriterien.
Steve
Was heißt //!pdas Drucken, wenn nicht eines der Dinge, die übereinstimmten?
David Conrad
1
Ah, verstanden, //wiederholt den letzten regulären Ausdruck , !nicht pdrucken. Nett.
David Conrad
0

Es ist markiert perlund ich sehe noch keine perlAntwort, also werde ich eingreifen.

Verwenden Sie keine regulären Ausdrücke oder andere "unstrukturierte" Parser. perlhat das JSONModul dabei. ( JSON::PPist seit 5.14 auch Teil des Kerns)

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

Natürlich würden Sie STDINeher aus oder einen Dateinamen lesen als DATAin Ihrem realen Nutzungsszenario.

Sobrique
quelle