Regex với lệnh sed để phân tích văn bản json


15

Tôi có văn bản json này:

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

Tôi muốn trích xuất trạng thái chung của buildStatus, tức là đầu ra dự kiến ​​là "LRI"

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

Tôi đã thử biểu thức sed bên dưới, nhưng nó không hoạt động, nó trả về OK:

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

Tôi đang làm gì sai?

Câu trả lời:


16

Không phân tích các cấu trúc dữ liệu lồng nhau phức tạp như JSON hoặc XML bằng các biểu thức thông thường, hãy sử dụng trình phân tích cú pháp JSON thích hợp, như jshon.

Đầu tiên bạn cần cài đặt nó:

sudo apt-get install jshon

Sau đó, bạn phải cung cấp cho nó dữ liệu JSON để phân tích cú pháp thông qua đầu vào tiêu chuẩn, do đó bạn có thể chuyển hướng đầu ra của một lệnh khác ở đó bằng một đường ống ( |) hoặc chuyển hướng một tệp đến nó ( < filename).

Các đối số cần thiết để trích xuất dữ liệu bạn muốn trông như thế này:

jshon -e "buildStatus" -e "status" -u
  • -e "buildStatus" chọn phần tử với chỉ mục "buildStatus" từ từ điển cấp cao nhất.
  • -e "status" chọn phần tử có chỉ mục "trạng thái" từ từ điển cấp hai được chọn ở trên.
  • -u chuyển đổi dữ liệu đã chọn từ JSON thành dữ liệu đơn giản (nghĩa là ở đây nó sẽ loại bỏ các trích dẫn xung quanh chuỗi)

Vì vậy, lệnh bạn chạy, tùy thuộc vào nơi bạn lấy dữ liệu từ đó, trông giống như một trong số đó:

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

Để tìm hiểu thêm về jshon, bạn có thể đọc trang chủ của nó có thể truy cập trực tuyến tại đây hoặc chỉ cần gõ man jshon.


6
Ngoài ra còn có jq:jq -r .buildStatus.status
muru


@HTNW Tôi chưa bao giờ thích câu trả lời đó, vì "thẻ mở XML đơn" (đó là câu hỏi thường gặp) ngôn ngữ thông thường (về nguyên tắc bạn có thể xây dựng trình phân tích cú pháp XML đầy đủ bằng cách sử dụng biểu thức chính quy để khớp thẻ, nhận xét, cdata các phần và sử dụng một ngăn xếp đơn giản để xử lý bối cảnh lồng nhau). Tuy nhiên, ngôn ngữ thông thường 'thú vị' nhất trong JSON là một chuỗi ký tự.
Random832

10

Công việc cho jq:

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

Có thể rút ngắn thành:

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

-r( --raw-output) xuất chuỗi không có jsonđịnh dạng chuỗi tức là không có dấu ngoặc kép.

Thí dụ:

% 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

Nếu chưa được cài đặt, hãy cài đặt nó bằng (có sẵn trong kho Vũ trụ):

sudo apt-get install jq 

8

Như đã đề cập, phân tích dữ liệu có cấu trúc phức tạp là tốt hơn với API thích hợp. Python có jsonmô-đun cho điều đó, cá nhân tôi sử dụng khá nhiều trong các tập lệnh của mình và khá dễ dàng để trích xuất các trường bạn muốn như vậy:

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

Điều xảy ra ở đây là chúng tôi chuyển hướng tệp đầu vào sang stdin của python và đọc nó với json.load(). Nó trở thành một từ điển python có khóa "buildStatus" và nó chứa một từ điển python khác với khóa "status". Do đó, chúng tôi chỉ đơn thuần là in ra giá trị của một khóa trong một từ điển được lưu trữ trong một từ điển khác. Khá đơn giản.

Bên cạnh sự đơn giản, một ưu điểm khác là python và API này đều được cài đặt sẵn và đi kèm với Ubuntu theo mặc định.


6

Bạn thực sự có thể làm điều này sed, nhưng tôi rất khuyến khích bạn sử dụng một ngôn ngữ phức tạp hơn có các công cụ được viết để xử lý dữ liệu JSON. Bạn có thể thử perl hoặc python chẳng hạn.

Bây giờ, trong ví dụ đơn giản của bạn, tất cả những gì bạn muốn là lần xuất hiện đầu tiên "status", vì vậy bạn có thể làm:

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

Mẹo nhỏ là sử dụng -nđể tránh in, sau đó nếu dòng khớp status( /status/), bạn xóa mọi thứ trừ phần bạn muốn s/.*:\s*"(.*)",/\1/, pxé dòng và quit.


Cá nhân, tôi thấy lệnh grep tương đương này đơn giản hơn nhiều:

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

Hoặc cái này:

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

Nghiêm túc mà nói, nếu bạn dự định phân tích cú pháp các tệp JSON, đừng cố làm điều này bằng tay. Sử dụng một trình phân tích cú pháp JSON thích hợp.


hoặc cái này:grep -m 1 status file.json | tr -cd '[[:alnum:]]:' | cut -f2 -d':'
Slowko

1
@ user1876040 bạn được chào đón. Hãy nhớ chấp nhận một trong những câu trả lời (Tôi khuyên ByteCommander's , đây là một giải pháp tốt hơn) để câu hỏi có thể được đánh dấu là đã trả lời).
terdon

6

Không nói rằng bạn nên sử dụng sed(tôi nghĩ rằng ai đó đã hạ thấp tôi chỉ vì không viết lời cảnh báo bắt buộc), nhưng, nếu bạn cần tìm kiếm một cái gì đó trên dòng tiếp theobuildStatus vì bạn dường như đang cố gắng trong nỗ lực của mình, bạn cần nói sedđể đọc dòng tiếp theo với Nlệnh

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

Ghi chú:

  • -n không in bất cứ điều gì cho đến khi chúng tôi yêu cầu
  • -rsử dụng ERE (giống như -E)
  • /buildStatus/N tìm mẫu này và đọc dòng tiếp theo
  • s/old/new/thay thế oldbằngnew
  • .* bất kỳ số lượng của bất kỳ ký tự trên dòng
  • \n dòng mới
  • : "(.*)",lưu bất kỳ ký tự xảy ra giữa : "",
  • \1 tham chiếu lại cho mẫu đã lưu
  • p in phần chúng tôi làm việc

0

Có một lời giải thích điển hình về lý do tại sao sedvà các công cụ xử lý luồng văn bản tương tự không được trang bị tốt để phân tích dữ liệu có cấu trúc như JSON và XML. Tôi không có trong tay, nhưng nó ở ngoài đó và tôi tin rằng vấn đề là các biểu thức cần thiết trong tất cả nhưng có lẽ là ít tình huống nhanh chóng trở nên rất phức tạp, trong khi các công cụ thay thế được xây dựng đặc biệt để phân tích cấu trúc thì nhiều hơn thanh lịch, dễ đọc và hiệu quả ở cùng một phân tích cú pháp.

Giống như muru đã đưa ra một nhận xét , jqnên là công cụ phù hợp cho công việc. Tôi cũng có thể bảo đảm rằng cá nhân tôi rất phấn khích khi thấy nó thay thế nhiều lần khi tôi đã thử phân tích cùng một dữ liệu để gần như không có hoặc thành công nặng nề. Nó thậm chí còn chứa một lượng lớn về khả năng định dạng và kiểm soát đầu ra. Tôi thích nó jsontoolvì một lý do hoặc nhiều hơn mà tôi hiện đang quên.

Byte Commander dường như đề nghị jshontrong một câu trả lời khác . Tôi chưa sử dụng công cụ đó, nhưng nó nhắc tôi xmlstarletvà cú pháp của nó, cũng với một số bản trình bày có thể tùy chỉnh cho đầu ra.


Có lẽ bạn đang nói về stackoverflow.com/a/1732454/2072269
muru

3
Xem xét cải thiện câu trả lời của bạn bằng cách hiển thị ví dụ về cách jsontoolcó thể được sử dụng cho trường hợp cụ thể của OP
Sergiy Kolodyazhnyy

Lol @muru, chính xác, đó là một trong những bài viết cố gắng ngăn chặn việc sử dụng phân tích cú pháp XML / JSON bằng Regex! Tôi đã khuyến nghị nhiều hơn jqrằng muru và heemayl mô tả rằng đã có exmap, và chỉ đăng lý do đằng sau nó: Askubfox.com/a/863948/230721
Pysis

0

Chỉ cần một công cụ Json khác gọi là json ( https://github.com/trentm/json )

$ json buildStatus.status < file.json
ERROR

Nghiên cứu trường hợp này là sai lệch: có vẻ như các công cụ không hoạt động. Bạn cũng có thể sử dụng jsonđể thay đổi tập tin json:

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

hoặc thậm chí ...

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

tài liệu trong: http://trentm.com/json/


nếu không được cài đặt:

  • cài đặt nút
  • và sudo npm install -g json
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.