awk / sed / perl one liner + come stampare solo le righe delle proprietà dal file json


10

come stampare solo le righe delle proprietà dal file json

esempio di 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"
      }
    }
  ]

uscita prevista

    "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
Domanda correlata su SO: analisi di JSON con strumenti Unix
hoefling

Risposte:


33

Jq è lo strumento giusto per l'elaborazione dei dati JSON:

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

L'output:

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

Nel caso in cui sia davvero obbligatorio ottenere ogni chiave e valore tra virgolette doppie, utilizzare la seguente modifica:

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

L'output:

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

Si consiglia di utilizzare uno strumento ( jq) consapevole della sintassi anziché operazioni di stringa ingenue, il che è buono, ma poi si utilizza un'operazione di stringa ingenua per eseguire (limitato) l'elaborazione della sequenza di escape per l'output. Non mi sembra una buona idea. jqdeve avere un modo per sfuggire correttamente al valore per l'output, giusto?
Daniel Pryden,

@DanielPryden, No. Sebbene jqabbia alcuni modi per sfuggire correttamente al valore per l'output (come @text, @shecc.), Questi non aiuteranno in questo caso particolare.
RomanPerekhrest,

Una variante che lascia i valori delle proprietà come oggetti JSON e utilizza sed per rimuovere le parentesi graffe e gli spazi bianchi indesiderati:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet,

perché "," non viene visualizzato nell'output, come i miei risultati previsti?
yael,

puoi vedere per favore il mio "risultato atteso", puoi modificare la tua risposta in base ai miei risultati previsti?
yael

27

Per favore, non prendere l'abitudine di analizzare i dati strutturati con strumenti non strutturati. Se stai analizzando XML, JSON, YAML ecc., Usa un parser specifico, almeno per convertire i dati strutturati in un modulo più appropriato per AWK sed, grepecc.

In questo caso, gronsarebbe di grande aiuto:

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

(È possibile post-elaborarlo con | cut -d. -f4- | gron --ungronper ottenere qualcosa di molto vicino all'output desiderato, anche se comunque come JSON valido.)

jqè anche appropriato .


2

Da Sed - Introduzione e tutorial di Bruce Barnett :

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

Per una corrispondenza più esatta e per occuparti anche della chiusura delle linee di parentesi con spazi bianchi aggiuntivi che puoi utilizzare

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

Non ho familiarità con JSON ma forse /}/è più sicuro di /}$. Quest'ultimo sembra non avere alcun vantaggio comunque.
Hauke ​​Laging,

1
@HaukeLaging Senza l'indicatore di fine riga corrisponde già alla contentlinea che contiene un punto }.
Nohillside,

5
Anche se è possibile, molto probabilmente funzionerà solo sul file di esempio . Se vuoi analizzare i dati strutturati, dovresti piuttosto usare qualcosa progettato per quello. Che si tratti di jq, xpath, yq, xq, ecc. Questo perché analizzarlo con strumenti orientati alla linea alla fine ti morderà nella parte posteriore e il debug potrebbe non essere molto semplice.
nert

Ad esempio, cosa succede se uno dei campi 'href' contiene la parola "proprietà"?
Stig Hemmer,

1
@StigHemmer Ecco perché ho esteso lo schema nel secondo esempio. Ma sono totalmente d'accordo sul fatto che usare grono jqsia l'approccio migliore.
Nohillside,

2

seduna fodera. Stampa le linee tra espressione regolare properties(es. Linea contenente "proprietà") ed espressione regolare ^ *}(es. Linea che inizia con zero o più spazi seguita da "}" e fine della linea).

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

awk una fodera.

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

forse potresti spiegare come funziona la corrispondenza dei tuoi pattern.
vfbsilva,

1
Sebbene funzioni per il file di esempio fornito, è rischioso tentare di analizzare JSON con strumenti che non lo comprendono. Ad esempio, cosa succede se uno dei campi 'href' contiene la parola "proprietà"? È molto meno soggetto a bug rispetto a uno strumento compatibile con JSON come le risposte più votate.
Stig Hemmer,

3
D'accordo, rischioso. Ma OP ha voluto specificamente una soluzione one-liner usando sed / awk / perl. La risposta che ho dato soddisfa tutti questi criteri.
steve

Cosa //!psignifica? Stampa se non una delle cose corrispondenti?
David Conrad,

1
Ah, capito, //ripete l'ultimo regex, !no, pstampa. Simpatico.
David Conrad,

1

È taggato perle non vedo perlancora nessuna risposta, quindi accedo.

Non usare espressioni regolari o altri parser "non strutturati". perlha il JSONmodulo con esso. ( JSON::PPfa parte del core anche dalla 5.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"
      }
    }
  ]
}

Naturalmente avresti letto STDINo un nome file anziché DATAnel tuo scenario di utilizzo reale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.