awk / sed / perl one liner + cómo imprimir solo las líneas de propiedades del archivo json


10

cómo imprimir solo las líneas de propiedades del archivo json

ejemplo de archivo 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"
      }
    }
  ]

Rendimiento esperado

    "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
Pregunta relacionada sobre SO: análisis de JSON con herramientas Unix
hoefling

Respuestas:


33

Jq es la herramienta adecuada para procesar datos JSON:

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

La salida:

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

En caso de que sea realmente obligatorio obtener cada clave y valor entre comillas dobles, use la siguiente modificación:

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

La salida:

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

Usted aboga por usar una herramienta compatible con la sintaxis ( jq) en lugar de operaciones de cadena ingenuas, lo cual es bueno, pero luego usa una operación de cadena ingenua para hacer un procesamiento de secuencia de escape (limitado) para la salida. Eso no me parece una buena idea. jqdebe tener una manera de escapar correctamente del valor de salida, ¿verdad?
Daniel Pryden

@DanielPryden, No. Aunque jqtiene algunas formas de escapar adecuadamente del valor de salida (como @text, @shetc.), eso no ayudará en este caso particular.
RomanPerekhrest

Una variante que deja los valores de las propiedades como objetos JSON y usa sed para eliminar los corchetes y espacios en blanco no deseados:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet

¿por qué "," no aparece en la salida, como mis resultados esperados?
yael

¿puedes ver mi "resultado esperado", puedes editar tu respuesta de acuerdo con mis resultados esperados?
yael

27

Por favor, no se acostumbre a analizar datos estructurados con herramientas no estructuradas. Si está analizando XML, JSON, YAML, etc., use un analizador específico, al menos para convertir los datos estructurados en una forma más apropiada para AWK sed, grepetc.

En este caso, gronsería de gran ayuda:

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

(Puede postprocesar esto | cut -d. -f4- | gron --ungronpara obtener algo muy cercano a la salida deseada, aunque todavía sea un JSON válido).

jqTambién es apropiado .


2

De Sed - Introducción y tutorial de Bruce Barnett :

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

Para una coincidencia más exacta y también para encargarse de cerrar las líneas de paréntesis con espacios en blanco adicionales, puede usar

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

No estoy familiarizado con JSON, pero tal vez /}/sea ​​más seguro que /}$. Este último parece no tener ninguna ventaja de todos modos.
Hauke ​​Laging

1
@HaukeLaging Sin el marcador de fin de línea, ya coincide con la contentlínea que contiene un }lugar.
nohillside

55
Aunque es posible, lo más probable es que solo funcione en el archivo de ejemplo . Si desea analizar datos estructurados, debería usar algo diseñado para eso. Ya sea jq, xpath, yq, xq, etc. Esto se debe a que analizarlo con herramientas orientadas a la línea eventualmente lo morderá en la parte posterior y la depuración que puede no ser muy fácil.
nert

Por ejemplo, ¿qué sucede si uno de los campos 'href' contiene la palabra "propiedades"?
Stig Hemmer

1
@StigHemmer Por eso extendí el patrón en el segundo ejemplo. Pero estoy totalmente de acuerdo en que usar grono jqes el mejor enfoque.
nohillside

2

sedun trazador de líneas. Imprima líneas entre la expresión regular properties(es decir, la línea que contiene "propiedades") y la expresión regular ^ *}(es decir, la línea que comienza con cero o más espacios seguidos de "}" y el final de la línea).

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

awk un trazador de líneas.

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

tal vez podrías explicar cómo funciona tu coincidencia de patrones.
vfbsilva

1
Si bien esto funciona para el archivo de ejemplo dado, es arriesgado intentar analizar JSON con herramientas que no lo entienden. Por ejemplo, ¿qué sucede si uno de los campos 'href' contiene la palabra "propiedades"? Es mucho menos propenso a errores a una herramienta compatible con JSON como las respuestas más votadas.
Stig Hemmer

3
De acuerdo, arriesgado. Pero OP específicamente quería una solución de una línea usando sed / awk / perl. La respuesta que he dado cumple con todos estos criterios.
Steve

Que //!psignifica Imprimir si no una de las cosas que coinciden?
David Conrad

1
Ah, lo tengo, //repite la última expresión regular, !no, pimprimir. Bonito.
David Conrad

1

Está etiquetado perl, y perltodavía no veo respuesta, así que lo incluiré.

No use expresiones regulares u otros analizadores 'no estructurados'. perltiene el JSONmódulo con él. (también JSON::PPforma parte del núcleo desde 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, leería STDINo un nombre de archivo en lugar de DATAen su escenario de uso real.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.