Разбор JSON с инструментами Unix - PullRequest
717 голосов
/ 24 декабря 2009

Я пытаюсь проанализировать JSON, возвращенный из запроса curl, например:

curl 'http://twitter.com/users/username.json' |
    sed -e 's/[{}]/''/g' | 
    awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'

Вышеприведенный код разбивает JSON на поля, например:

% ...
"geo_enabled":false
"friends_count":245
"profile_text_color":"000000"
"status":"in_reply_to_screen_name":null
"source":"web"
"truncated":false
"text":"My status"
"favorited":false
% ...

Как напечатать определенное поле (обозначается -v k=text)?

Ответы [ 36 ]

4 голосов
/ 07 декабря 2011

Вы можете попробовать что-то вроде этого -

curl -s 'http://twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '$1~/"text"/ {print}'
4 голосов
/ 01 апреля 2014

Для более сложного анализа JSON я предлагаю использовать модуль python jsonpath (автор Stefan Goessner) -

  1. Установите его -

sudo easy_install -U jsonpath

  1. Используйте это -

Пример file.json (из http://goessner.net/articles/JsonPath) -

{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

Разобрать (извлечь все названия книг с ценой <10) - </p>

$ cat file.json | python -c "import sys, json, jsonpath; print '\n'.join(jsonpath.jsonpath(json.load(sys.stdin), 'store.book[?(@.price < 10)].title'))"

Будет выводить -

Sayings of the Century
Moby Dick

ПРИМЕЧАНИЕ. Приведенная выше командная строка не включает проверку ошибок. для полного решения с проверкой ошибок вы должны создать небольшой скрипт на python и обернуть код с помощью try-exc.

4 голосов
/ 18 ноября 2015

Если у вас есть php :

php -r 'var_export(json_decode(`curl http://twitter.com/users/username.json`, 1));'

Например:
у нас есть ресурс, который предоставляет json iso-коды стран: http://country.io/iso3.json, и мы легко можем увидеть его в оболочке с curl:

curl http://country.io/iso3.json

но выглядит не очень удобно и не читабельно, лучше разбирать json и видеть читаемую структуру:

php -r 'var_export(json_decode(`curl http://country.io/iso3.json`, 1));'

Этот код напечатает что-то вроде:

array (
  'BD' => 'BGD',
  'BE' => 'BEL',
  'BF' => 'BFA',
  'BG' => 'BGR',
  'BA' => 'BIH',
  'BB' => 'BRB',
  'WF' => 'WLF',
  'BL' => 'BLM',
  ...

если у вас есть вложенные массивы, этот вывод будет выглядеть намного лучше ...

Надеюсь, это поможет ...

4 голосов
/ 11 ноября 2017

Есть более простой способ получить свойство из строки json. Используя package.json файл в качестве примера, попробуйте это:

#!/usr/bin/env bash
my_val="$(json=$(<package.json) node -pe "JSON.parse(process.env.json)['version']")"

Мы используем process.env, потому что это позволяет получить содержимое файла в node.js в виде строки без риска того, что вредоносное содержимое выйдет из их цитирования и будет проанализировано как код.

4 голосов
/ 26 апреля 2017

Это еще один bash & python гибридный ответ. Я опубликовал этот ответ, потому что хотел обработать более сложный вывод JSON, но, уменьшив сложность моего приложения bash. Я хочу взломать следующий объект JSON из http://www.arcgis.com/sharing/rest/info?f=json в bash:

{
  "owningSystemUrl": "http://www.arcgis.com",
  "authInfo": {
    "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
    "isTokenBasedSecurity": true
  }
}

Хотя этот подход увеличивает сложность функции Python, использование bash упрощается:

function jsonGet {
  python -c 'import json,sys
o=json.load(sys.stdin)
k="'$1'"
if k != "":
  for a in k.split("."):
    if isinstance(o, dict):
      o=o[a] if a in o else ""
    elif isinstance(o, list):
      if a == "length":
        o=str(len(o))
      elif a == "join":
        o=",".join(o)
      else:
        o=o[int(a)]
    else:
      o=""
if isinstance(o, str) or isinstance(o, unicode):
  print o
else:
  print json.dumps(o)
'
}

curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo.tokenServicesUrl

Вывод приведенного выше сценария:

Я добавил поддержку массивов, поэтому вы можете использовать .length и, если источником является строковый массив, вы можете использовать .join:

curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.23

Какие выходы:

  • 1
  • [{"scale": 591657527.591555, "resolution": 156543.03392800014, "level": 0}, {"scale": 295828763.795777, "resolution": 78271.51696399994, "level": 1}, {"scale": 147914381.8978899 , "разрешение": 39135.75848200009, "уровень": 2}, {"масштаб": 73957190.948944, "разрешение": 19567.87924099992, "уровень": 3}, {"масштаб": 36978595.474472, "разрешение": 9783.93962049996, "уровень" : 4}, {"scale": 18489297.737236, "resolution": 4891.96981024998, "level": 5}, {"scale": 9244648.868618, "resolution": 2445.98490512499, "level": 6}, {"scale": 4622324.434309 , "resolution": 1222.992452562495, "level": 7}, {"scale": 2311162.217155, "resolution": 611.4962262813797, "level": 8}, {"scale": 1155581.108577, "resolution": 305.74811314055756, "level" : 9}, {"scale": 577790.554289, "resolution": 152.87405657041106, "level": 10}, {"scale": 288895.277144, "resolution": 76.43702828507324, "level": 11}, {"scale": 144447.638572 , "resolution": 38.21851414253662, "level": 12}, {"scale": 72223.819286, "resolution": 19.1092570 7126831, "уровень": 13}, {"масштаб": 36111.909643, "разрешение": 9.554628535634155, "уровень": 14}, {"масштаб": 18055.954822, "разрешение": 4.77731426794937, "уровень": 15}, { "scale": 9027.977411, "resolution": 2.388657133974685, "level": 16}, {"scale": 4513.988705, "resolution": 1.1943285668550503, "level": 17}, {"scale": 2256.994353, "resolution": 0.5971642835598172, "уровень": 18}, {"масштаб": 1128.497176, "разрешение": 0.29858214164761665, "уровень": 19}, {"масштаб": 564.248588, "разрешение": 0.14929107082380833, "уровень": 20}, { «масштаб»: 282.124294, «разрешение»: 0.07464553541190416, «уровень»: 21}, {«масштаб»: 141.062147, «разрешение»: 0.03732276770595208, «уровень»: 22}, {«масштаб»: 70.5310735, «разрешение»: 0,01866138385297604, "уровень": 23}]
  • 24
  • {"scale": 70.5310735, "resolution": 0.01866138385297604, "level": 23}
3 голосов
/ 25 января 2018

Существует также очень простой, но мощный JSON CLI инструмент обработки fx - https://github.com/antonmedv/fx

Example of JSON formatting in Bash terminal

Примеры

Использовать анонимную функцию:

$ echo '{"key": "value"}' | fx "x => x.key"
value

Если вы не передадите анонимную функцию param => ..., код будет автоматически преобразован в анонимную функцию. И вы можете получить доступ к JSON по этому ключевому слову:

$ echo '[1,2,3]' | fx "this.map(x => x * 2)"
[2, 4, 6]

Или просто используйте точечный синтаксис:

$ echo '{"items": {"one": 1}}' | fx .items.one
1

Вы можете передать любое количество анонимных функций для сокращения JSON:

$ echo '{"items": ["one", "two"]}' | fx "this.items" "this[1]"
two

Вы можете обновить существующий JSON с помощью оператора распространения:

$ echo '{"count": 0}' | fx "{...this, count: 1}"
{"count": 1}

Просто JavaScript . Не нужно изучать новый синтаксис.


ОБНОВЛЕНИЕ 2018-11-06

fx теперь имеет интерактивный режим (! )

image

https://github.com/antonmedv/fx

3 голосов
/ 03 февраля 2014

Синтаксический анализ JSON является болезненным в сценарии оболочки. С более подходящим языком создайте инструмент, который извлекает атрибуты JSON в соответствии с соглашениями сценариев оболочки. Вы можете использовать свой новый инструмент для решения непосредственной проблемы со сценариями оболочки, а затем добавить его в свой комплект для будущих ситуаций.

Например, рассмотрим инструмент jsonlookup , такой, что если я скажу jsonlookup access token id, он вернет атрибут id , определенный в атрибуте token , определенном в атрибут access из stdin, который предположительно является данными JSON. Если атрибут не существует, инструмент ничего не возвращает (состояние выхода 1). Если синтаксический анализ завершился неудачно, выйдите из состояния 2 и отправьте сообщение в stderr. Если поиск выполнен успешно, инструмент печатает значение атрибута.

Создав инструмент Unix для точной цели извлечения значений JSON, вы можете легко использовать его в сценариях оболочки:

access_token=$(curl <some horrible crap> | jsonlookup access token id)

Любой язык подойдет для реализации jsonlookup . Вот довольно лаконичная версия Python:

#!/usr/bin/python                                                               

import sys
import json

try: rep = json.loads(sys.stdin.read())
except:
    sys.stderr.write(sys.argv[0] + ": unable to parse JSON from stdin\n")
    sys.exit(2)
for key in sys.argv[1:]:
    if key not in rep:
        sys.exit(1)
    rep = rep[key]
print rep
3 голосов
/ 15 сентября 2014

Это хороший вариант использования для pythonpy :

curl 'http://twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'
3 голосов
/ 04 декабря 2014

Двухслойный, который использует Python. Это особенно хорошо работает, если вы пишете один файл .sh и не хотите зависеть от другого файла .py. Это также использует использование трубы |. echo "{\"field\": \"value\"}" может быть заменено чем-либо, печатающим json на стандартный вывод.

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'
3 голосов
/ 27 августа 2016

Если в системе доступно pip, то:

$ pip install json-query

Примеры использования:

$ curl -s http://0/file.json | json-query
{
    "key":"value"    
}

$ curl -s http://0/file.json | json-query my.key
value

$ curl -s http://0/file.json | json-query my.keys.
key_1
key_2
key_3

$ curl -s http://0/file.json | json-query my.keys.2
value_2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...