awk / sed / perl one liner + วิธีพิมพ์เฉพาะบรรทัดคุณสมบัติจากไฟล์ 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
คำถามที่เกี่ยวข้องกับ SO: การวิเคราะห์ JSON ด้วยเครื่องมือ Unix
ยกหู

ยังเกี่ยวข้องกับ: stackoverflow.com/questions/1732348/…
Kartik

คำตอบ:


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"

ในกรณีที่จำเป็นจริง ๆ ในการขอรับแต่ละคีย์และค่า double-quote ให้ใช้การแก้ไขต่อไปนี้:

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ต้องมีวิธีที่จะหลบหนีค่าอย่างถูกต้องสำหรับการส่งออกใช่ไหม
Daniel Pryden

@DanielPryden เลขที่แม้ว่าjqจะมีวิธีการบางอย่างที่จะต้องหลบหนีค่าสำหรับการส่งออก (เช่น@text, @shฯลฯ ) เหล่านั้นจะไม่ช่วยในกรณีนี้โดยเฉพาะอย่างยิ่ง
RomanPerekhrest

ตัวแปรที่ทำให้ค่าคุณสมบัติเป็นวัตถุ JSON และใช้ sed ในการตัดวงเล็บปีกกาและช่องว่างที่ไม่ต้องการ:jq '.items[].properties' input.json | sed -n 's/^\s\+//p'
Joe Lee-Moyet

ทำไม "," ไม่ปรากฏในผลลัพธ์เนื่องจากผลลัพธ์ที่ฉันคาดไว้
yael

คุณเห็นหรือไม่โปรด "เอาท์พุทที่คาดหวัง" ของฉันคุณสามารถแก้ไขคำตอบของคุณตามผลลัพธ์ที่คาดหวังได้หรือไม่?
yael

27

ได้โปรดได้โปรดอย่านิสัยชอบวิเคราะห์ข้อมูลที่มีโครงสร้างด้วยเครื่องมือที่ไม่มีโครงสร้าง หากคุณกำลังวิเคราะห์ XML, JSON, YAML ฯลฯ ใช้ parser ที่เฉพาะเจาะจงอย่างน้อยการแปลงข้อมูลที่มีโครงสร้างเป็นรูปแบบที่เหมาะสมมากขึ้นสำหรับ 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 - คำแนะนำและการสอนโดย Bruce Barnett :

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

สำหรับการจับคู่ที่แม่นยำยิ่งขึ้นและเพื่อดูแลไลน์การปิดวงเล็บด้วยช่องว่างเพิ่มเติมที่คุณสามารถใช้ได้

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

ผมไม่คุ้นเคยกับ JSON แต่อาจจะปลอดภัยกว่า/}/ /}$หลังดูเหมือนว่าจะไม่มีข้อได้เปรียบใด ๆ อยู่แล้ว
Hauke ​​Laging

1
@HaukeLaging หากไม่มีตัวทำเครื่องหมายจุดสิ้นสุดบรรทัดแล้วจะตรงกับcontentบรรทัดที่มีที่}ใดที่หนึ่งอยู่แล้ว
nohillside

5
แม้ว่าจะเป็นไปได้ แต่ส่วนใหญ่จะใช้ได้กับไฟล์ตัวอย่างเท่านั้น ถ้าคุณต้องการแยกวิเคราะห์ข้อมูลที่มีโครงสร้างคุณควรใช้สิ่งที่ออกแบบมาสำหรับมัน ไม่ว่าจะเป็น jq, xpath, yq, xq เป็นต้นเพราะการแยกวิเคราะห์ด้วยเครื่องมือที่เน้นเส้นจะกัดคุณที่ด้านหลังและแก้จุดบกพร่องซึ่งอาจไม่ใช่เรื่องง่าย
nert

ตัวอย่างเช่นจะเกิดอะไรขึ้นหากหนึ่งในฟิลด์ '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-aware เช่นคำตอบที่ได้รับคะแนนสูงสุด
เฮมเมอร์

3
ยอมรับความเสี่ยง แต่ OP ต้องการโซลูชันหนึ่งซับโดยใช้ sed / awk / perl คำตอบที่ฉันได้รับตรงตามเกณฑ์เหล่านี้ทั้งหมด
สตีฟ

อะไร//!pหมายถึง? พิมพ์หากไม่ใช่สิ่งที่ตรงกันหรือไม่
David Conrad

1
อ่าเข้าใจแล้ว//ทำซ้ำ regex สุดท้าย!ไม่ใช่pพิมพ์ ดี
David Conrad

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ในสถานการณ์การใช้งานจริงของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.