it-swarm.com.ru

Разбор JSON с инструментами Unix

Я пытаюсь проанализировать 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)?

710
auser

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

curl -s 'https://api.github.com/users/lambda' | jq -r '.name'

Вы также можете сделать это с помощью инструментов, которые, вероятно, уже установлены в вашей системе, например Python с использованием json module , и, таким образом, избегать любых дополнительных зависимостей, сохраняя при этом преимущество правильный анализатор JSON. Далее предполагается, что вы хотите использовать UTF-8, в который должен быть закодирован исходный JSON и который используется большинством современных терминалов:

Python 2:

export PYTHONIOENCODING=utf8
curl -s 'https://api.github.com/users/lambda' | \
    python -c "import sys, json; print json.load(sys.stdin)['name']"

Python 3:

curl -s 'https://api.github.com/users/lambda' | \
    python3 -c "import sys, json; print(json.load(sys.stdin)['name'])"

Исторические заметки

Первоначально этот ответ рекомендовался jsawk , который все еще должен работать, но его использование немного более громоздко, чем jq, и зависит от устанавливаемого автономного интерпретатора JavaScript, который встречается реже, чем Python интерпретатор, поэтому приведенные выше ответы, вероятно, предпочтительнее:

curl -s 'https://api.github.com/users/lambda' | jsawk -a 'return this.name'

В этом ответе также изначально использовался API-интерфейс Twitter из этого вопроса, но этот API-интерфейс больше не работает, что затрудняет копирование примеров для тестирования, а новому API-интерфейсу Twitter требуются ключи API, поэтому я перешел к использованию GitHub API, который можно легко использовать без ключей API. Первый ответ на оригинальный вопрос будет:

curl 'http://Twitter.com/users/username.json' | jq -r '.text'
851
Brian Campbell

Чтобы быстро извлечь значения для конкретного ключа, мне лично нравится использовать "grep -o", который возвращает только совпадение с регулярным выражением. Например, чтобы получить поле "текст" из твитов, что-то вроде:

grep -Po '"text":.*?[^\\]",' tweets.json

Это регулярное выражение более надежно, чем вы думаете; например, он прекрасно работает со строками, имеющими запятые и экранированные кавычки внутри них. Я думаю, немного проделав работу, вы могли бы сделать такую, которая действительно гарантированно извлечет значение, если оно атомарное. (Если у него есть вложенность, то регулярное выражение не может сделать это, конечно.)

А для дальнейшей очистки (хотя и сохраняя исходное экранирование строки) вы можете использовать что-то вроде: | Perl -pe 's/"text"://; s/^"//; s/",$//'. (Я сделал это для этот анализ .)

Всем ненавистникам, которые настаивают на том, что вы должны использовать настоящий анализатор JSON - да, это важно для правильности, но

  1. Чтобы провести действительно быстрый анализ, например, подсчет значений для проверки ошибок очистки данных или общее представление о данных, вывести что-то в командную строку быстрее. Открытие редактора для написания сценария отвлекает.
  2. grep -o на несколько порядков быстрее, чем стандартная библиотека json Python, по крайней мере при выполнении этого для твитов (каждый размером ~ 2 КБ). Я не уверен, что это только потому, что json медленный (я должен сравнить с yajl когда-нибудь); но в принципе регулярное выражение должно быть быстрее, поскольку оно имеет конечное состояние и гораздо более оптимизируемое, а не синтаксический анализатор, который должен поддерживать рекурсию, и в этом случае тратит много деревьев построения ЦП для структур, которые вас не интересуют. (Если бы кто-то написал преобразователь конечного состояния, который выполнял правильный (ограниченный по глубине) анализ JSON, это было бы замечательно! Тем временем у нас есть "grep -o".)

Для написания поддерживаемого кода я всегда использую настоящую библиотеку синтаксического анализа. Я не пробовал jsawk , но если он работает хорошо, это будет точка № 1.

И последнее, более причудливое решение: я написал скрипт, который использует Python json и извлекает нужные ключи в столбцы, разделенные табуляцией; затем я передаю обертку вокруг awk, которая разрешает именованный доступ к столбцам. Здесь: сценарии json2tsv и tsvawk . Так что для этого примера это будет:

json2tsv id text < tweets.json | tsvawk '{print "Tweet " $id " is: " $text}'

Этот подход не касается # 2, он более неэффективен, чем отдельный скрипт Python, и он немного ломкий: он заставляет нормализовать переводы строк и табуляции в строковых значениях, чтобы играть в Nice с полем/записью awk ограниченный взгляд на мир. Но это позволяет вам оставаться в командной строке с большей корректностью, чем grep -o.

255
Brendan OConnor

На основании того, что некоторые из рекомендаций здесь (особенно в комментариях) предполагают использование Python, я был разочарован тем, что не нашел примера.

Итак, вот один вкладыш для получения одного значения из некоторых данных JSON. Предполагается, что вы передаете данные (откуда-то) и поэтому должны быть полезны в контексте сценариев.

echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hostname"]'
159
paulkmoore

Вслед за MartinR и Бекко лидируют:

$ curl -s 'http://Twitter.com/users/username.json' | python -mjson.tool

Это даст вам невероятно дружественный вывод. Очень удобно:

$ curl -s 'http://Twitter.com/users/username.json' | python -mjson.tool | grep my_key
124
jnrg

Вы можете просто скачать двоичный файл jq для вашей платформы и запустить (chmod +x jq):

$ curl 'https://Twitter.com/users/username.json' | ./jq -r '.name'

Он извлекает атрибут "name" из объекта json.

jq homepage говорит, что это похоже на sed для данных JSON.

119
jfs

Используйте поддержка JSON в Python вместо использования awk!

Что-то вроде этого:

curl -s http://Twitter.com/users/username.json | \
    python -c "import json,sys;obj=json.load(sys.stdin);print obj['name'];"
93
martinr

Использование Node.js

Если в системе установлено узел , можно использовать флаги сценариев печати -p и -e с помощью JSON.parse для извлечения любого необходимого значения.

Простой пример использования строки JSON { "foo": "bar" } и извлечения значения "foo":

$ node -pe 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
bar

Поскольку у нас есть доступ к cat и другим утилитам, мы можем использовать это для файлов:

$ node -pe 'JSON.parse(process.argv[1]).foo' "$(cat foobar.json)"
bar

Или любой другой формат, такой как URL, который содержит JSON:

$ node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"
Trevor Senior
89
JayQuerie.com

Вы спросили, как выстрелить себе в ногу, и я здесь, чтобы предоставить боеприпасы:

curl -s 'http://Twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^text/ {print $2}'

Вы можете использовать tr -d '{}' вместо sed. Но полное их исключение, похоже, также дает желаемый эффект.

Если вы хотите удалить внешние кавычки, передайте результат вышеупомянутого через sed 's/\(^"\|"$\)//g'

Я думаю, что другие забили достаточно тревоги. Я буду стоять с сотовым телефоном, чтобы вызвать скорую помощь. Огонь, когда готов.

53
Dennis Williamson

Использование Bash с Python

Создайте функцию bash в вашем файле .bash_rc

function getJsonVal () { 
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))"; 
}

Затем

$ curl 'http://Twitter.com/users/username.json' | getJsonVal "['text']"
My status
$ 

Здесь та же функция, но с проверкой ошибок.

function getJsonVal() {
   if [ \( $# -ne 1 \) -o \( -t 0 \) ]; then
       cat <<EOF
Usage: getJsonVal 'key' < /tmp/
 -- or -- 
 cat /tmp/input | getJsonVal 'key'
EOF
       return;
   fi;
   python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}

Где $ # -ne 1 обеспечивает как минимум 1 ввод, а -t 0 - перенаправление из канала.

Приятной особенностью этой реализации является то, что вы можете получить доступ к вложенным значениям json и получить взамен json! знак равно

Пример:

$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']['a'][1]"
2

Если вы хотите быть по-настоящему модным, вы можете просто напечатать данные:

function getJsonVal () { 
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1, sort_keys=True, indent=4))"; 
}

$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']"
{
    "a": [
        1, 
        2, 
        3
    ], 
    "bar": "baz"
}
40
Joe Heyming

TickTick - это анализатор JSON, написанный на bash (<250 строк кода)

Вот отрывок автора из его статьи Представьте себе мир, в котором Bash поддерживает JSON :

#!/bin/bash
. ticktick.sh

``  
  people = { 
    "Writers": [
      "Rod Serling",
      "Charles Beaumont",
      "Richard Matheson"
    ],  
    "Cast": {
      "Rod Serling": { "Episodes": 156 },
      "Martin Landau": { "Episodes": 2 },
      "William Shatner": { "Episodes": 2 } 
    }   
  }   
``  

function printDirectors() {
  echo "  The ``people.Directors.length()`` Directors are:"

  for director in ``people.Directors.items()``; do
    printf "    - %s\n" ${!director}
  done
}   

`` people.Directors = [ "John Brahm", "Douglas Heyes" ] ``
printDirectors

newDirector="Lamont Johnson"
`` people.Directors.Push($newDirector) ``
printDirectors

echo "Shifted: "``people.Directors.shift()``
printDirectors

echo "Popped: "``people.Directors.pop()``
printDirectors
25
CoolAJ86

Разбор JSON с помощью PHP CLI

Возможно, не по теме, но, поскольку царит приоритет, этот вопрос остается неполным без упоминания о нашем верном и верном PHP, я прав?

Используя тот же пример JSON, но давайте присвоим его переменной, чтобы уменьшить затенение.

$ export JSON='{"hostname":"test","domainname":"example.com"}'

Теперь для блага PHP, используя file_get_contents и упаковщик потока php: // stdin .

$ echo $JSON|php -r 'echo json_decode(file_get_contents("php://stdin"))->hostname;'

или, как указано с помощью fgets и уже открытого потока с константой CLI STDIN .

$ echo $JSON|php -r 'echo json_decode(fgets(STDIN))->hostname;'

nJoy!

19
nickl-

Родная версия Bash: также хорошо работает с обратной косой чертой (\) и кавычками (")

function parse_json()
{
    echo $1 | \
    sed -e 's/[{}]/''/g' | \
    sed -e 's/", "/'\",\"'/g' | \
    sed -e 's/" ,"/'\",\"'/g' | \
    sed -e 's/" , "/'\",\"'/g' | \
    sed -e 's/","/'\"---SEPERATOR---\"'/g' | \
    awk -F=':' -v RS='---SEPERATOR---' "\$1~/\"$2\"/ {print}" | \
    sed -e "s/\"$2\"://" | \
    tr -d "\n\t" | \
    sed -e 's/\\"/"/g' | \
    sed -e 's/\\\\/\\/g' | \
    sed -e 's/^[ \t]*//g' | \
    sed -e 's/^"//'  -e 's/"$//'
}


parse_json '{"username":"john, doe","email":"[email protected]"}' username
parse_json '{"username":"john doe","email":"[email protected]"}' email

--- outputs ---

john, doe
[email protected]
18
maikel

Версия, в которой используются Ruby и ​​ http://flori.github.com/json/

$ < file.json Ruby -e "require 'rubygems'; require 'json'; puts JSON.pretty_generate(JSON[STDIN.read]);"

или более кратко:

$ < file.json Ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"
12
boecko

К сожалению, ответ с наибольшим количеством голосов, использующий grep, возвращает совпадение полное, которое не сработало в моем сценарии, но если вы знаете, что формат JSON останется постоянным, вы можете использовать lookbehind и lookahead , чтобы извлечь только нужные значения.

# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="FooBar":")(.*?)(?=",)'
he\"llo
# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="TotalPages":)(.*?)(?=,)'
33
#  echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="anotherValue":)(.*?)(?=})'
100
10
Daniel Sokolowski

Теперь, когда Powershell является кроссплатформенным, я подумал, что смогу найти выход, так как считаю его довольно интуитивным и чрезвычайно простым.

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json 

ConvertFrom-Json преобразует JSON в пользовательский объект Powershell, поэтому вы можете легко работать со свойствами с этого момента. Например, если вам нужно только свойство id, вы просто сделаете это:

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json | select -ExpandProperty id

Если вы хотите вызвать все это изнутри Bash, то вам придется называть это так:

powershell 'curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json'

Конечно, есть чистый способ Powershell сделать это без curl, который будет:

Invoke-WebRequest 'https://api.github.com/users/lambda' | select -ExpandProperty Content | ConvertFrom-Json

Наконец, есть также ConvertTo-Json, который так же легко преобразует пользовательский объект в JSON. Вот пример:

(New-Object PsObject -Property @{ Name = "Tester"; SomeList = @('one','two','three')}) | ConvertTo-Json

Который будет производить хороший JSON, как это:

{
"Name":  "Tester",
"SomeList":  [
                 "one",
                 "two",
                 "three"
             ]

}

По общему признанию, использование Windows Shell в Unix несколько кощунственно, но Powershell действительно хорош в некоторых вещах, и разбор JSON и XML - пара из них. Это страница GitHub для кроссплатформенной версии https://github.com/PowerShell/PowerShell

6
user2233949

Я не могу использовать ни один из ответов здесь. Нет доступных jq, нет массивов Shell, нет объявлений, нет grep -P, нет look -hind и lookahead, нет Python, нет Perl, нет Ruby, нет - даже Bash ... Остальные ответы просто не работают должным образом. JavaScript звучит знакомо, но в банке написано Nescaffe - так что это тоже не пойдет :) Даже если таковые имеются, для моей простой необходимости - они будут излишними и медленными.

Тем не менее, для меня чрезвычайно важно получить много переменных из ответа моего модема в формате json. Я делаю это в sh с очень урезанным BusyBox на моих маршрутизаторах! Нет проблем с использованием только awk: просто установите разделители и прочитайте данные. Для одной переменной это все!

awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json

Помните, у меня нет массивов? Я должен был присвоить анализируемые в awk данные 11 переменным, которые мне нужны в сценарии Shell. Куда бы я ни посмотрел, это считалось невозможной миссией. С этим тоже проблем нет.

Мое решение простое. Этот код будет: 1) анализировать файл .json из вопроса (на самом деле, я позаимствовал образец рабочих данных из наиболее часто задаваемого ответа) и выбрать данные в кавычках, плюс 2) создать переменные Shell из awk, присваивая бесплатную именованную Shell имена переменных.

eval $( curl -s 'https://api.github.com/users/lambda' | 
awk ' BEGIN { FS="\""; RS="," };
{
    if ($2 == "login") { print "Login=\""$4"\"" }
    if ($2 == "name") { print "Name=\""$4"\"" }
    if ($2 == "updated_at") { print "Updated=\""$4"\"" }
}' )
echo "$Login, $Name, $Updated"

Никаких проблем с пробелами внутри. В моем случае эта же команда анализирует длинный однострочный вывод. Поскольку используется eval, это решение подходит только для доверенных данных. Его легко адаптировать для сбора данных без кавычек. Для огромного числа переменных, предельное увеличение скорости может быть достигнуто с помощью else if. Отсутствие массива, очевидно, означает: нет нескольких записей без лишних действий. Но там, где имеются массивы, адаптация этого решения - простая задача.

@maikel sed ответ почти работает (но я не могу это комментировать). Для моих красиво отформатированных данных - это работает. Не так много с примером, использованным здесь (пропущенные кавычки отбрасывают его). Это сложно и сложно изменить. Кроме того, мне не нравится делать 11 вызовов для извлечения 11 переменных. Зачем? Я рассчитал 100 циклов, извлекая 9 переменных: функция sed заняла 48.99 с, а мое решение заняло 0.91 с! Не честно? Выполнение только одного извлечения из 9 переменных: 0,51 против 0,02 сек.

5
Pila

Кто-то, у кого также есть XML-файлы, может захотеть взглянуть на мой Xidel . Это cli, процессор без зависимостей JSONiq . (т.е. он также поддерживает XQuery для обработки XML или JSON)

Пример в вопросе будет:

 xidel -e 'json("http://Twitter.com/users/username.json")("name")'

Или с моим собственным нестандартным синтаксисом расширения:

 xidel -e 'json("http://Twitter.com/users/username.json").name'
5
BeniBela

Если кто-то просто хочет извлечь значения из простых объектов JSON без вложенных структур, можно использовать регулярные выражения, даже не выходя из bash.

Вот функция, которую я определил, используя регулярные выражения bash на основе стандарт JSON :

function json_extract() {
  local key=$1
  local json=$2

  local string_regex='"([^"\]|\\.)*"'
  local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
  local value_regex="${string_regex}|${number_regex}|true|false|null"
  local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"

  if [[ ${json} =~ ${pair_regex} ]]; then
    echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
  else
    return 1
  fi
}

Предостережения: объекты и массивы не поддерживаются как значения, но поддерживаются все другие типы значений, определенные в стандарте. Кроме того, пара будет сопоставлена ​​независимо от того, насколько глубоко она находится в документе JSON, если она имеет абсолютно одинаковое имя ключа.

Используя пример OP:

$ json_extract text "$(curl 'http://Twitter.com/users/username.json')"
My status

$ json_extract friends_count "$(curl 'http://Twitter.com/users/username.json')"
245
5
Helder Pereira

Вы можете использовать jshon :

curl 'http://Twitter.com/users/username.json' | jshon -e text
5
kev

Если у вас есть 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
Vladimir Kovpak

Есть более простой способ получить свойство из строки 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
Alexander Mills

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

curl -s 'http://Twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '$1~/"text"/ {print}'
4
jaypal singh

Это еще один гибридный ответ 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, "разрешение": 156543.03392800014, "уровень": 0}, {"масштаб": 295828763.795777, "разрешение": 78271.51696399994, "уровень": 1}, {"масштаб": 147914381.897889, "разрешение" ": 39135.75848200009," уровень ": 2}, {" масштаб ": 73957190.948944," разрешение ": 19567.87924099992," уровень ": 3}, {" масштаб ": 36978595.474472," разрешение ": 9783.93962049996," уровень ": 4} , {"scale": 18489297.737236, "разрешение": 4891.96981024998, "уровень": 5}, {"масштаб": 9244648.868618, "разрешение": 2445.98490512499, "уровень": 6}, {"масштаб": 4622324.434309, "разрешение" ": 1222.992452562495," уровень ": 7}, {" масштаб ": 2311162.217155," разрешение ": 611.4962262813797," уровень ": 8}, {" масштаб ": 1155581.108577," разрешение ": 305.74811314055756," уровень ": 9} , {"scale": 577790.554289, "разрешение": 152.87405657041106, "уровень": 10}, {"масштаб": 288895.277144, "разрешение": 76.43702828507324, "уровень": 11}, {"масштаб": 144447.638572, "разрешение" ": 38.21851414253662," уровень ": 12}, {" масштаб ": 72223.819286," разрешение ": 19.1092570712683 1, "уровень": 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}
4
Stephen Quan

вот один способ, которым вы можете сделать это с помощью awk

curl -sL 'http://Twitter.com/users/username.json' | awk -F"," -v k="text" '{
    gsub(/{|}/,"")
    for(i=1;i<=NF;i++){
        if ( $i ~ k ){
            print $i
        }
    }
}'
4
ghostdog74

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

  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) -

$ 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
shlomosh

Если 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
3
Alexey Dubkov

Существует также очень простой, но мощный 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 теперь имеет интерактивный режим (! )

https://github.com/antonmedv/fx

3
Anton Medvedev

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

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

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

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
mcnabicus

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

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'
3
Adam Kurkiewicz

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

curl 'http://Twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'
3
RussellStewart

я использовал это для извлечения длительности видео из вывода ffprobe json:

MOVIE_INFO=`ffprobe "path/to/movie.mp4"  -show_streams -show_format -print_format json -v quiet` 
MOVIE_SECONDS=`echo "$MOVIE_INFO"|grep -w \"duration\" |tail -1 | cut -d\" -f4 |cut -d \. -f 1`

его можно использовать для извлечения значения из любого json:

value=`echo "$jsondata"|grep -w \"key_name\" |tail -1 | cut -d\" -f4
2
Ehsan Chavoshi

Вот хорошая ссылка . В этом случае:

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++) { where = match(a[i], /\"text\"/); if(where) {print a[i]} }  }'
2
Max Barrass

Вы можете использовать bashJson

Это оболочка для json-модуля Python и может обрабатывать сложные данные json.

Давайте рассмотрим этот пример данных JSON из файла test.json

 {
 "имя": "Инструмент тестирования", 
 "автор": "hack4mer", 
 "support_os": {
 "osx ": {
" foo ":" bar ", 
" min_version ": 10.12, 
" test_on ": [10.1,10.13] 
}, 
 "ubuntu": {
 "min_version": 14.04, 
 "test_on": 16.04 
} 
} 
} 

Следующие команды читают данные из этого примера файла json

./bashjson.sh test.json name

Печать: Тестовый инструмент

./bashjson.sh test.json supported_os osx foo

Принты: бар

./bashjson.sh test.json supported_os osx tested_on

Печать: [10.1,10.13]

1
hack4mer

Я сделал это, "анализируя" ответ json для определенного значения, следующим образом:

curl $url | grep $var | awk '{print $2}' | sed s/\"//g 

Ясно, что $ url здесь будет URL Twitter, а $ var будет "text", чтобы получить ответ для этой переменной.

На самом деле, я думаю, что единственное, что я делаю в OP, это grep для строки с конкретной переменной, которую он ищет. Awk берет второй элемент в строке, и с помощью sed я убираю кавычки.

Кто-то умнее меня, вероятно, мог бы все мыслить с помощью awk или grep.

Теперь вы можете сделать все это с помощью sed:

curl $url | sed '/text/!d' | sed s/\"text\"://g | sed s/\"//g | sed s/\ //g

таким образом, нет awk, нет grep ... Я не знаю, почему я не думал об этом раньше. Хммм ...

1
tonybaldwin

Мне нужно было что-то короткое в BASH, и оно работало бы без зависимостей, кроме Vanilla Linux LSB и Mac OS, для python 2.7 & 3 и обрабатывало ошибки, например. сообщит об ошибках синтаксического анализа json и об отсутствующих свойствах без исключений python:

json-extract () {
  if [[ "$1" == "" || "$1" == "-h" || "$1" == "-?" || "$1" == "--help" ]] ; then
    echo 'Extract top level property value from json document'
    echo '  Usage: json-extract <property> [ <file-path> ]'
    echo '  Example 1: json-extract status /tmp/response.json'
    echo '  Example 2: echo $JSON_STRING | json-extract-file status'
    echo '  Status codes: 0 - success, 1 - json parse error, 2 - property missing'
  else
    python -c $'import sys, json;\ntry: obj = json.load(open(sys.argv[2])); \nexcept: sys.exit(1)\ntry: print(obj[sys.argv[1]])\nexcept: sys.exit(2)' "$1" "${2:-/dev/stdin}"
  fi
}
1
Mike

Niet - это инструмент, который помогает вам извлекать данные из файла json или yaml непосредственно в CLI Shell/bash.

$ pip install niet

Рассмотрим файл json с именем project.json со следующим содержимым:

{
  project: {
    meta: {
      name: project-sample
    }
}

Вы можете использовать Niet, как это:

$ PROJECT_NAME=$(niet project.json project.meta.name)
$ echo ${PROJECT_NAME}
project-sample
1
Herve