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

Я спробував вираз sed нижче, але він не працює, він повертається OK:

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

Що я роблю неправильно?

Відповіді:


16

Не розбирайте складні вкладені структури даних, такі як JSON або XML, з регулярними виразами, використовуйте належний аналізатор JSON, наприклад jshon.

Спочатку потрібно встановити його:

sudo apt-get install jshon

Тоді вам потрібно надати йому дані JSON для розбору за допомогою стандартного вводу, щоб ви могли або перенаправити висновок іншої команди туди через pipe ( |), або перенаправити файл на нього ( < 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, ви можете прочитати його сторінку, доступну в Інтернеті, тут, або просто набравши текст man jshon.


6
Там також jq:jq -r .buildStatus.status
муру


@HTNW мені ніколи не сподобалася ця відповідь, тому що "єдиний відкритий тег XML" (саме до цього питання задається) - це звичайна мова (і ви могли, в принципі, створити повний аналізатор XML, використовуючи регулярні вирази для позначення тегів, коментарів, даних розділи та використання простого стека для обробки вкладеного контексту). Однак найбільш "цікавою" регулярною мовою в JSON є рядкова буква.
Випадково832

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 python, і читаємо це за допомогою json.load(). Це стає словником python з ключем "buildStatus", і він містить ще один словник python з клавішею "status". Таким чином, ми просто роздруковуємо значення ключа в словнику, який зберігається в іншому словнику. Досить просто.

Крім простоти, ще одна перевага полягає в тому, що python і цей 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обрисуйте рядокq .


Особисто я вважаю цю еквівалентну команду 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's , його є кращим рішенням), щоб питання можна було позначити як відповідь).
тердон

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. Я не маю цього під рукою, але він є там, і я вважаю, що справа в тому, що вирази, необхідні в усіх, але, мабуть, найменших ситуаціях, швидко стають дуже складними, тоді як альтернативних інструментів, побудованих спеціально для розбору структури, більше елегантний, читабельний та ефективний при одночасному розборі.

Як Муру , коментуючи коментар , jqмає стати правильним інструментом для роботи. Я також можу поручитися за те, що я дуже схвильований, коли його кілька разів замінюють, коли я намагався проаналізувати одні й ті самі дані, щоб майже не досягти або обтяжувати успіх. Він навіть містить велику кількість можливостей для форматування та контролю в іншому випадку. Я вважаю за краще це з jsontoolтієї причини, яку я зараз забуваю.

Байта-командир, здається, рекомендує jshonв іншій відповіді . Я не використовував цей інструмент, але він нагадує мені xmlstarletі його синтаксис, також з деякою настроюваною презентацією для виводу.


Ви , напевно , говорити про stackoverflow.com/a/1732454/2072269
Муру

3
Поміркуйте над покращенням своєї відповіді, показавши приклад того, як jsontoolможна використовувати для конкретного випадку ОП
Сергій Колодяжний,

Lol @muru, правильно, це один з дописів, який намагається стримувати використання від аналізу XML / JSON з Regex! Я більше рекомендував jqмуру та хемайлу описати, що вже мають приклади, і просто розміщувати міркування за ним: 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/


якщо не встановлено:

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