awk / sed / perl one liner + cách chỉ in các dòng thuộc tính từ tệp json


10

Làm thế nào để chỉ in các dòng thuộc tính từ tập tin json

ví dụ về tập tin 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"
      }
    }
  ]

sản lượng dự kiến

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


Câu trả lời:


33

Jq là công cụ phù hợp để xử lý dữ liệu JSON:

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

Đầu ra:

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

Trong trường hợp nếu thực sự bắt buộc phải lấy từng khóa và giá trị được trích dẫn kép - hãy sử dụng sửa đổi sau:

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

Đầu ra:

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

Bạn ủng hộ việc sử dụng một công cụ nhận biết cú pháp ( jq) thay vì các thao tác chuỗi ngây thơ, điều này tốt, nhưng sau đó bạn sử dụng một hoạt động chuỗi ngây thơ để thực hiện (giới hạn) xử lý chuỗi thoát cho đầu ra. Đó dường như không phải là một ý tưởng tốt cho tôi. jqphải có cách thoát giá trị cho đầu ra đúng không?
Daniel Pryden

@DanielPryden, Không. Mặc dù jqcó một số cách để thoát đúng giá trị cho đầu ra (như @text, @shv.v.), nhưng chúng sẽ không giúp ích trong trường hợp cụ thể này.
RomanPerekhrest

Một biến thể để lại các giá trị thuộc tính dưới dạng các đối tượng JSON và sử dụng sed để loại bỏ các dấu ngoặc và khoảng trắng không mong muốn:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet

tại sao "," không xuất hiện trong đầu ra, như kết quả mong đợi của tôi?
yael

bạn có thể xem "đầu ra dự kiến" của tôi không, bạn có thể chỉnh sửa câu trả lời của mình theo kết quả mong đợi của tôi không?
yael

26

Xin vui lòng, đừng có thói quen phân tích dữ liệu có cấu trúc bằng các công cụ phi cấu trúc. Nếu bạn đang phân tích cú pháp XML, JSON, YAML, v.v., hãy sử dụng một trình phân tích cú pháp cụ thể, ít nhất là để chuyển đổi dữ liệu có cấu trúc thành một dạng thích hợp hơn cho AWK sed, grepv.v.

Trong trường hợp này, gronsẽ giúp rất nhiều:

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

(Bạn có thể xử lý hậu kỳ này | cut -d. -f4- | gron --ungronđể có được thứ gì đó rất gần với đầu ra mong muốn của bạn, mặc dù vẫn là JSON hợp lệ.)

jqcũng thích hợp .


2

Từ Sed - Giới thiệu và hướng dẫn của Bruce Barnett :

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

Để khớp chính xác hơn và cũng quan tâm đến việc đóng các dòng khung với khoảng trắng bổ sung mà bạn có thể sử dụng

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

Tôi không quen thuộc với JSON nhưng có lẽ /}/an toàn hơn /}$. Cái sau dường như không có bất kỳ lợi thế nào.
Hauke ​​Laging

1
@HaukeLaging Không có điểm đánh dấu cuối dòng, nó đã khớp với contentdòng có chứa một }nơi nào đó.
nohillside

5
Mặc dù có thể, rất có thể nó sẽ chỉ hoạt động trên tệp ví dụ . Nếu bạn muốn phân tích dữ liệu có cấu trúc, bạn nên sử dụng một cái gì đó được thiết kế cho điều đó. Có thể là jq, xpath, yq, xq, v.v.
nert

Ví dụ: điều gì xảy ra nếu một trong các trường 'href' chứa từ "thuộc tính"?
Stig Hemmer

1
@StigHemmer Đó là lý do tại sao tôi mở rộng mẫu trong ví dụ thứ hai. Nhưng tôi hoàn toàn đồng ý rằng sử dụng gronhoặc jqlà cách tiếp cận tốt hơn.
nohillside

2

sedlót. In các dòng giữa biểu thức chính quy properties(tức là dòng chứa "thuộc tính") và biểu thức chính quy ^ *}(tức là dòng bắt đầu bằng 0 hoặc nhiều khoảng trắng theo sau "}" và cuối dòng).

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

awk lót.

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

có lẽ bạn có thể giải thích làm thế nào để khớp mẫu của bạn hoạt động.
vfbsilva

1
Mặc dù điều này hoạt động với tệp ví dụ được cung cấp, nhưng thật nguy hiểm khi cố phân tích JSON bằng các công cụ không hiểu nó. Ví dụ: điều gì xảy ra nếu một trong các trường 'href' chứa từ "thuộc tính"? Nó ít bị lỗi hơn đối với một công cụ nhận biết JSON như các câu trả lời được bình chọn hàng đầu.
Stig Hemmer

3
Đồng ý, mạo hiểm. Nhưng OP đặc biệt muốn một giải pháp một lớp lót sử dụng sed / awk / perl. Câu trả lời tôi đã đưa ra đáp ứng tất cả các tiêu chí này.
steve

//!pnghĩa là gì? In nếu không phải là một trong những điều phù hợp?
David Conrad

1
Ah, hiểu rồi, //lặp lại regex cuối cùng, !không, pin. Đẹp.
David Conrad

0

Nó được gắn thẻ perlvà tôi không thấy perlcâu trả lời nào, vì vậy tôi sẽ gắn chip vào.

Không sử dụng các biểu thức thông thường hoặc các trình phân tích cú pháp 'không cấu trúc' khác. perlJSONmô-đun với nó. ( JSON::PPcũng là một phần của lõi kể từ 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"
      }
    }
  ]
}

Đương nhiên, bạn sẽ đọc từ STDINhoặc một tên tệp chứ không phải DATAtrong kịch bản sử dụng thực tế của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.