awk / sed / perl один вкладиш + як друкувати лише рядки властивостей з файлу 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
Питання по
темі

Також пов’язано: stackoverflow.com/questions/1732348/…
Картик

Відповіді:


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повинен мати спосіб належним чином уникнути значення для виводу, правда?
Даніель Приден

@DanielPryden, Ні. Хоча jqє деякі способи, як правильно уникнути значення для виводу (наприклад @text, @shтощо), вони не допоможуть у цьому конкретному випадку.
RomanPerekhrest

Варіант, який залишає значення властивостей як об'єктів JSON і використовує sed для позбавлення небажаних дужок і пробілів:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Джо Лі-Моєт

чому "," не відображається у висновку, як очікувані результати?
yael

чи бачите, будь ласка, мій "очікуваний вихід", чи можете ви відредагувати свою відповідь відповідно до моїх очікуваних результатів?
yael

27

Будь ласка, не вживайте звички аналізувати структуровані дані неструктурованими інструментами. Якщо ви розбираєте XML, JSON, YAML і т.д., використовувати конкретний аналізатор, по крайней мере , для перетворення структурованих даних в більш відповідну форму для AWK, sed, і grepт.д.

У цьому випадку 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

From Sed - Вступ та підручник Брюса Барнетта :

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

Для більш точної відповідності, а також для подбання про закриття дужок з додатковим пробілом, який ви можете використовувати

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

Я не знайомий з JSON, але, можливо, /}/це безпечніше /}$. Останнє, схоже, не має жодних переваг.
Хоуке Лагінг

1
@HaukeLaging Без маркера кінця рядка він вже відповідає contentрядку, який }десь містить .
nohillside

5
Хоча це можливо, він, швидше за все, працює лише на прикладі . Якщо ви хочете проаналізувати структуровані дані, скоріше скористайтеся чимось, призначеним для цього. Будь то jq, xpath, yq, xq тощо. Це тому, що розбір його за допомогою інструментів, орієнтованих на лінійку, врешті-решт кусає вас у спину та налагоджує, що може бути не дуже простим.
Нерт

Наприклад, що станеться, якщо одне з полів 'href' містить слово "властивості"?
Стіг Хеммер

1
@StigHemmer Ось чому я продовжив схему у другому прикладі. Але я повністю погоджуюся, що використовувати gronабо jqє кращим підходом.
nohillside

2

sedодин лайнер. Друкуйте рядки між регулярним виразом properties(тобто рядком, що містить "властивості") та регулярним виразом ^ *}(тобто рядком, що починається з нуля або більше пробілів, а потім "}" та кінцем рядка).

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

awk один лайнер.

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

можливо, ви могли б пояснити, як працює ваша відповідність шаблону.
vfbsilva

1
Хоча це працює для наведеного прикладу, ризиковано намагатись розібрати JSON інструментами, які його не розуміють. Наприклад, що станеться, якщо одне з полів 'href' містить слово "властивості"? Набагато менше схильних до помилок, відомих JSON, як відповіді з голосовими відгуками.
Стиг Хеммер

3
Погодьтеся, ризиковано. Але ОП спеціально хотіла однолінійного рішення, використовуючи sed / awk / perl. Відповідь, яку я дав, відповідає всім цим критеріям.
Стів

Що //!pозначає? Роздрукуйте, якщо не одна з речей, які відповідали?
Девід Конрад

1
Ах, отримав це, //повторює останній вираз, а !не, pдрук. NIce.
Девід Конрад

1

Він позначений тегом perl, і я ще не бачу perlвідповіді, тож я підключуся.

Не використовуйте регулярні вирази чи інші "неструктуровані" аналізатори. perlмає JSONмодуль з ним. ( JSON::PPє частиною ядра з 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"
      }
    }
  ]
}

Звичайно, ви читаєте з STDINабо ім'я файлу, а не DATAв реальному сценарії використання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.