Regex ด้วยคำสั่ง sed เพื่อแยกข้อความ json


15

ฉันมีข้อความ json นี้:

{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

ฉันต้องการที่จะแยกสถานะโดยรวมของ buildStatus คือเอาท์พุทที่คาดหวังคือ "ข้อผิดพลาด"

"buildStatus" : {
    "status" : "ERROR",
    ....
}

ฉันลองใช้นิพจน์ด้านล่าง แต่มันใช้งานไม่ได้ผลตอบแทนOK:

status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile

ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


16

อย่าแยกซับซ้อนโครงสร้างข้อมูลที่ซ้อนกันเช่น JSON หรือ XML ที่มีการแสดงออกปกติใช้ parser JSON jshonที่เหมาะสมเช่น

ก่อนอื่นคุณต้องติดตั้ง:

sudo apt-get install jshon

จากนั้นคุณต้องจัดเตรียมข้อมูล JSON เพื่อแยกวิเคราะห์ผ่านอินพุตมาตรฐานดังนั้นคุณสามารถเปลี่ยนทิศทางเอาต์พุตของคำสั่งอื่นที่นั่นด้วยไพพ์ ( |) หรือเปลี่ยนเส้นทางไฟล์ไปที่มัน ( < filename)

อาร์กิวเมนต์ที่ต้องการแยกข้อมูลที่คุณต้องการให้มีลักษณะดังนี้:

jshon -e "buildStatus" -e "status" -u
  • -e "buildStatus" เลือกองค์ประกอบด้วยดัชนี "buildStatus" จากพจนานุกรมระดับบนสุด
  • -e "status" เลือกองค์ประกอบที่มีดัชนี "สถานะ" จากพจนานุกรมระดับที่สองที่เลือกด้านบน
  • -u แปลงข้อมูลที่เลือกจาก JSON เป็นข้อมูลธรรมดา (เช่นที่นี่จะลบเครื่องหมายคำพูดรอบ ๆ สตริง)

ดังนั้นคำสั่งที่คุณเรียกใช้ขึ้นอยู่กับตำแหน่งที่คุณรับข้อมูลดูเหมือนว่าหนึ่งในนั้น:

jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u

ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับjshonคุณสามารถอ่าน manpage ของออนไลน์สามารถเข้าถึงที่นี่man jshonหรือโดยเพียงแค่พิมพ์


6
นอกจากนี้ยังมีjq:jq -r .buildStatus.status
muru


@HTNW ฉันไม่เคยชอบคำตอบนั้นเพราะ "single tag open XML" (ซึ่งเป็นคำถามที่ถาม) เป็นภาษาปกติ (และในหลักการคุณสามารถสร้างตัวแยกวิเคราะห์ XML แบบเต็มโดยใช้ regexes เพื่อจับคู่แท็กความคิดเห็น cdata ส่วนและใช้กองซ้อนง่าย ๆ เพื่อจัดการบริบทซ้อนกัน) อย่างไรก็ตามภาษาปกติ 'ที่น่าสนใจที่สุด' ใน JSON เป็นตัวอักษรสตริง
Random832

10

งานสำหรับjq:

jq -r '.["buildStatus"]["status"]' file.json

สามารถย่อให้เหลือ:

jq -r '.buildStatus.status' file.json

-r( --raw-output) เอาท์พุทสตริงโดยไม่ต้องjsonจัดรูปแบบสตริงเช่นไม่มีคำพูด

ตัวอย่าง:

% cat file.json                   
{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

% jq -r '.["buildStatus"]["status"]' file.json
ERROR

% jq -r '.buildStatus.status' file.json       
ERROR

หากยังไม่ได้ติดตั้งให้ติดตั้งโดย (มีอยู่ในที่เก็บข้อมูล Universe):

sudo apt-get install jq 

8

ดังที่ได้กล่าวมาแล้วการแยกวิเคราะห์ข้อมูลที่มีโครงสร้างที่ซับซ้อนนั้นดีกว่าด้วย API ที่เหมาะสม Python มีjsonโมดูลสำหรับสิ่งนั้นซึ่งโดยส่วนตัวแล้วฉันใช้สคริปต์ค่อนข้างเยอะและมันง่ายมากที่จะแยกฟิลด์ที่คุณต้องการดังนี้

$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' <  input.txt
ERROR

จะเกิดอะไรขึ้นที่นี่เป็นที่ที่เราเปลี่ยนเส้นทางไปยังแฟ้มใส่ stdin json.load()หลามและอ่านด้วย สิ่งนี้กลายเป็นพจนานุกรมหลามที่มีคีย์ "buildStatus" และมีพจนานุกรมหลามอีกตัวที่มีปุ่ม "สถานะ" ดังนั้นเราเพียงแค่พิมพ์ค่าของคีย์ในพจนานุกรมที่เก็บไว้ในพจนานุกรมอื่น ค่อนข้างง่าย

นอกเหนือจากความเรียบง่ายข้อดีอีกอย่างคือหลามและ API นี้ติดตั้งล่วงหน้าทั้งหมดและมาพร้อมกับ Ubuntu เป็นค่าเริ่มต้น


6

คุณสามารถทำสิ่งนี้ได้จริงsedแต่ฉันขอแนะนำให้คุณใช้ภาษาที่ซับซ้อนกว่าซึ่งมีเครื่องมือที่เขียนขึ้นเพื่อจัดการกับข้อมูล JSON ตัวอย่างเช่นคุณสามารถลอง perl หรือ python

ในตัวอย่างง่ายๆของคุณสิ่งที่คุณต้องการคือสิ่งที่เกิดขึ้นครั้งแรก"status"ดังนั้นคุณสามารถทำได้:

$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json 
ERROR

เคล็ดลับคือการใช้-nเพื่อหลีกเลี่ยงการพิมพ์จากนั้นหากเส้นตรงstatus( /status/) คุณลบทุกอย่างยกเว้นชิ้นส่วนที่คุณต้องการs/.*:\s*"(.*)",/\1/ให้pพิมพ์บรรทัดและquit


โดยส่วนตัวแล้วฉันพบว่าคำสั่ง grep ที่เทียบเท่านี้ง่ายกว่ามาก:

$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json 
ERROR

หรืออันนี้:

$ perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json 
ERROR

อย่างจริงจังแม้ว่าถ้าคุณวางแผนที่จะแยกวิเคราะห์ไฟล์ JSON อย่าพยายามทำด้วยตนเอง ใช้ตัวแยกวิเคราะห์ JSON ที่เหมาะสม


หรืออันนี้:grep -m 1 status file.json | tr -cd '[[:alnum:]]:' | cut -f2 -d':'
slowko

1
@ user1876040 ยินดีต้อนรับ โปรดจำไว้ว่าให้ยอมรับหนึ่งในคำตอบ (ฉันแนะนำByteCommanderซึ่งเป็นวิธีแก้ปัญหาที่ดีกว่า) เพื่อที่คำถามจะถูกทำเครื่องหมายเป็นคำตอบ)
terdon

6

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

$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR

หมายเหตุ:

  • -n อย่าพิมพ์อะไรจนกว่าเราจะขอมัน
  • -rใช้ ERE (เช่นเดียวกับ-E)
  • /buildStatus/N ค้นหารูปแบบนี้และอ่านบรรทัดถัดไปด้วย
  • s/old/new/แทนที่oldด้วยnew
  • .* จำนวนอักขระใด ๆ ในบรรทัด
  • \n ขึ้นบรรทัดใหม่
  • : "(.*)",บันทึกตัวละครใด ๆ ที่เกิดขึ้นระหว่าง: "และ",
  • \1 อ้างอิงกลับไปยังรูปแบบที่บันทึกไว้
  • p พิมพ์ส่วนที่เราทำงาน

0

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

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

Byte บัญชาการดูเหมือนว่าจะแนะนำjshonในคำตอบอื่น ฉันไม่ได้ใช้เครื่องมือนั้น แต่มันทำให้ฉันนึกถึงxmlstarletและซินแท็กซ์ของมันพร้อมกับการนำเสนอที่ปรับแต่งได้บางอย่างสำหรับผลลัพธ์


คุณอาจพูดถึงstackoverflow.com/a/1732454/2072269
muru

3
ลองปรับปรุงคำตอบของคุณโดยแสดงตัวอย่างว่าjsontoolจะใช้กับกรณีเฉพาะของ OP ได้อย่างไร
Sergiy Kolodyazhnyy

Lol @muru ถูกต้องซึ่งเป็นหนึ่งในโพสต์ที่พยายามขัดขวางการใช้งานจากการแยกวิเคราะห์ XML / JSON ด้วย Regex! ฉันแนะนำเพิ่มเติมjqว่า muru และ heemayl อธิบายว่ามี exmaples อยู่แล้วและเพิ่งโพสต์เหตุผลด้านหลัง: askubuntu.com/a/863948/230721
Pysis

0

เครื่องมือ Json อีกอันหนึ่งที่เรียกว่า json ( https://github.com/trentm/json )

$ json buildStatus.status < file.json
ERROR

กรณีศึกษานี้ทำให้เข้าใจผิด: ดูเหมือนว่าเครื่องมือไม่ทำงาน คุณยังสามารถใช้jsonสำหรับการเปลี่ยนไฟล์ json:

$ json -e 'this.buildStatus.status="not error"' < file.json > new.json

หรือแม้กระทั่ง...

$ json -e 'this.buildStatus.status="no errors"' < file.json | json -e 'this.buildStatus.status
no errors

เอกสารประกอบใน: http://trentm.com/json/


หากไม่ได้ติดตั้ง:

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