Разбор 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
)?
Ответы
Ответ 1
Существует несколько инструментов, специально предназначенных для управления JSON из командной строки, и будет намного проще и надежнее, чем делать с Awk, например jq
:
curl -s 'https://api.github.com/users/lambda' | jq -r '.name'
Вы также можете сделать это с помощью инструментов, которые, вероятно, уже установлены в вашей системе, например Python, с помощью модуля json
, и поэтому избегайте любых дополнительных зависимостей, при этом все еще пользуясь надлежащим парсером 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 требуются ключи API, поэтому я переключился на использование API GitHub, который можно легко использовать без ключей API. Первый ответ на исходный вопрос:
curl 'http://twitter.com/users/username.json' | jq -r '.text'
Ответ 2
Чтобы быстро извлечь значения для определенного ключа, мне лично нравится использовать "grep -o", который возвращает только соответствие регулярному выражению. Например, чтобы получить поле "текст" из твитов, например:
grep -Po '"text":.*?[^\\]",' tweets.json
Это регулярное выражение более надежное, чем вы думаете; например, он отлично разбирается со строками, имеющими встроенные запятые и скрытыми кавычками внутри них. Я думаю, что с немного дополнительной работой вы могли бы создать тот, который на самом деле гарантированно извлекает значение, если оно будет атомарным. (Если он имеет гнездование, то регулярное выражение не может этого сделать, конечно.)
И для дальнейшей очистки (хотя и сохранения оригинального экранирования строки) вы можете использовать что-то вроде: | perl -pe 's/"text"://; s/^"//; s/",$//'
. (Я сделал это для этот анализ.)
Для всех ненавистников, которые настаивают на том, что вы должны использовать настоящий парсер JSON - да, это важно для правильности, но
- Чтобы сделать действительно быстрый анализ, например, подсчитывать значения, чтобы проверять ошибки очистки данных или получать общее представление о данных, быстрее удалять что-то из командной строки. Открытие редактора для записи script отвлекает.
-
grep -o
на порядок быстрее, чем стандартная библиотека json
на Python, по крайней мере, когда вы делаете это для твитов (каждая составляет ~ 2 КБ). Я не уверен, что это просто потому, что json
медленный (я должен иногда сравнивать с yajl); но в принципе, регулярное выражение должно быть быстрее, поскольку оно является конечным состоянием и гораздо более оптимизированным, вместо парсера, который должен поддерживать рекурсию, и в этом случае тратит много деревьев на сборку зданий для структур, которые вам не нужны. (Если кто-то написал конечный преобразователь состояния, который сделал правильный (ограниченный глубиной) разбор JSON, это было бы фантастично! Тем временем у нас есть "grep -o".)
Чтобы написать поддерживаемый код, я всегда использую настоящую парсинговую библиотеку. Я не пробовал jsawk, но если он работает хорошо, это касается точки № 1.
Последнее, более wackier, решение: я написал script, который использует Python json
и извлекает нужные вам ключи, в столбцы с разделителями столбцов; затем я прохожу через обертку вокруг awk
, которая позволяет именованный доступ к столбцам. Здесь: скрипты json2tsv и tvvawk. Итак, для этого примера это будет:
json2tsv id text < tweets.json | tsvawk '{print "tweet " $id " is: " $text}'
Этот подход не относится к № 2, является более неэффективным, чем один Python script, и он немного хрупкий: он принудительно нормализует новые строки и вкладки в строковых значениях, чтобы играть хорошо с awk-полем/разделителем записей взгляд на мир. Но это позволяет вам оставаться в командной строке с большей точностью, чем grep -o
.
Ответ 3
На основании того, что некоторые из рекомендаций здесь (особенно в комментариях) предполагают использование Python, я был разочарован тем, что не нашел примера.
Итак, здесь один вкладыш для получения одного значения из некоторых данных JSON. Предполагается, что вы передаете данные (откуда-то) и поэтому должны быть полезны в контексте сценариев.
echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hostname"]'
Ответ 4
Следуя указаниям MartinR и Boecko:
$ 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
Ответ 5
Вы можете просто загрузить jq
двоичный файл для своей платформы и запустить (chmod +x jq
):
$ curl 'https://twitter.com/users/username.json' | ./jq -r '.name'
Он извлекает атрибут "name"
из объекта json.
jq
homepage говорит, что это похоже на sed
для данных JSON.
Ответ 6
Используйте поддержку Python JSON вместо использования awk!
Что-то вроде этого:
curl -s http://twitter.com/users/username.json | \
python -c "import json,sys;obj=json.load(sys.stdin);print obj['name'];"
Ответ 7
Использование Node.js
Если система имеет node, можно использовать флаги -p
print и -e
evaulate script с 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
Ответ 8
Вы спросили, как стрелять себе в ногу, и я здесь, чтобы предоставить боеприпасы:
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'
Я думаю, что другие услышали достаточную тревогу. Я буду стоять рядом с мобильным телефоном, чтобы вызвать скорую. Пожар при готовности.
Ответ 9
Использование 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"
}
Ответ 10
jq
$ curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | \
jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
Ответ 11
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
Ответ 12
Разбор JSON с PHP CLI
Возможно, не в тему, но поскольку приоритет царит, этот вопрос остается неполным без упоминания нашего надежного и верного PHP, я прав?
Используя тот же пример JSON, но давайте присваиваем его переменной для уменьшения неопределенности.
$ export JSON='{"hostname":"test","domainname":"example.com"}'
Теперь для PHP goodness, используя 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!
Ответ 13
Нативная версия 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]
Ответ 14
пожалуйста не делайте этого!
не используют линейно-ориентированные инструменты для анализа иерархических данных, сериализованных в текст. он работает только для особых случаев и будет преследовать вас и других людей. если вы действительно не можете использовать готовый json-парсер, напишите простой, используя рекурсивный спуск. это легко и будет выносить изменения, испускающая сторона справедливо рассматривает косметические (добавленные или удаленные пробелы, включая символы новой строки).
Ответ 15
Не изобретайте колесо и не выбирайте из официального инструмента анализа JSON, рекомендованного создателем JSON:
http://www.json.org/
(см. внизу)
Ответ 16
Версия, которая использует 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]);"
Ответ 17
Кажется, что все недооценивают awk. Правда, одного или двух строк awk script не хватит. Но нетрудно написать настоящий JSON-парсер в awk. Я просто добавил один из своих awkenough.
Ответ 18
Несколько лет спустя я предполагаю (извините), но я создал чистый bash script, который поддерживает вложенность и может легко получить значения.
Основная часть script:
curl "http://twitter.com/users/username.json" |
./JSON.sh |
grep -F -e "[\"text\"] |
cut -s -f 2 -d ' '
В рабочем каталоге script требуется JSON.sh.
Автор json-формата рекомендует использовать JSON.sh
в bash (перейдите в www.json.org и прокрутите вниз до второго раздела и он указан в разделе "Bash" ).
Если вы хотите, чтобы ваш script находился только в одном файле .sh
, вы можете скопировать и вставить команды throw
, parse_array
, parse_object
, parse_value
и parse
в ваш script.
Измените script на следующее:
curl "http://twitter.com/users/username.json" |
grep -aoE '\"[^[:cntrl:]"\\]*((\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})[^[:cntrl:]"\\]*)*\"|-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?|null|false|true|[[:space:]]+$|.' --color=never |
grep -vE '^[[:space:]]+' |
parse |
grep -F -e "[\"text\"] |
cut -s -f 2 -d ' '
Как это работает:
-
curl
получает json файл, затем передает его на grep
.
-
grep
"tokenizes" json (он выводит строку, число или символ и т.д.), а затем передает ее на второй grep
, чья задача состоит в том, чтобы съесть пробелы. Это не относится к вам, если вы не копируете функции из JSON.sh.
- Если вы копируете функции из JSON.sh, функция
parse
рекурсивно выводит путь к значению, затем вкладку, а затем значение. Если вы этого не сделаете, то JSON.sh выполняет токенизацию, ест пустоты и вызывает внутреннюю функцию parse
. Оба передают их вывод на grep
.
-
grep
ищет список ключей и значений для пары, которую вы хотите. Он ищет ключ и выводит строку с ключом и значением. Как форматируются ключи: [aKey], где aKey
- это ключ. Если ваш json вложен, он разделяется запятой. Если ваши значения находятся в массиве, используйте индекс массива (начиная с нуля), чтобы получить значение. Строка key/value переводится на cut
(используйте несколько экземпляров -e "[aKey]", чтобы получить сразу несколько значений).
-
cut
разрезает строку по два с помощью вкладки в качестве разделителя, а затем печатает только значение.
Таким образом, вы можете использовать только файл script и использовать чистый bash и поддерживать вложенный json
. Наслаждайтесь! (хотя теперь вы, вероятно, перешли к другим проектам).
Ответ 19
К сожалению, верхний проголосовавший ответ, который использует grep
, возвращает совпадение full, которое не работает в моем сценарии, но если вы знаете, что формат 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
Ответ 20
Я создал модуль, специально предназначенный для манипуляции JSON с командной строкой:
https://github.com/ddopson/underscore-cli
- FLEXIBLE. Инструмент "swiss-army-knife" для обработки данных JSON - может использоваться как простой симпатичный принтер или как полноценная Javascript-команда.
- МОЩНЫЙ - предоставляет полную мощность и функциональность underscore.js(плюс underscore.string)
- ПРОСТОЙ - упрощает запись однострочных JS, аналогичных использованию "perl -pe"
- CHAINED. Несколько команд-команд можно связать вместе для создания конвейера обработки данных.
- MULTI-FORMAT. Богатая поддержка форматов ввода/вывода - довольно-печатная, строгая JSON, msgpack и т.д.
- DOCUMENTED - отличная документация по командной строке с несколькими примерами для каждой команды
Выбор поля довольно прост:
cat file.json | underscore extract field.subfield.subsubfield
По умолчанию он будет печатать вывод с "smart-whitespace", который является как читаемым, так и 100% строгим JSON (но вы можете выбрать другие форматы с флагами):
Если у вас есть какие-либо функции, прокомментируйте это сообщение или добавьте проблему в github. Я был бы рад определить приоритеты функций, которые необходимы членам сообщества.
Ответ 21
Вы можете использовать jshon
:
curl 'http://twitter.com/users/username.json' | jshon -e text
Ответ 22
Кто-то, у кого также есть 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'
Ответ 23
Теперь, когда 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:
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 в Unix несколько кощунственно, но Powershell действительно хорош в некоторых вещах, и парсинг JSON и XML - это пара из них. Эта страница GitHub для кросс-платформенной версии https://github.com/PowerShell/PowerShell
Ответ 24
здесь один из способов сделать это с помощью 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
}
}
}'
Ответ 25
Вы можете попробовать что-то вроде этого -
curl -s 'http://twitter.com/users/jaypalsingh.json' |
awk -F=":" -v RS="," '$1~/"text"/ {print}'
Ответ 26
Для более сложного разбора JSON я предлагаю использовать модуль jsonpath python (by Stefan Goessner) -
sudo easy_install -U jsonpath
Пример 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 script и обернуть код с помощью try-except.
Ответ 27
Если у вас 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',
...
если у вас есть вложенные массивы, этот вывод будет выглядеть намного лучше...
Надеюсь, это поможет...
Ответ 28
Это еще один гибридный ответ 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
Выходной сигнал выше script:
Я добавил поддержку массивов, поэтому вы можете использовать .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.897889, "resolution" : 39135.75848200009, "level" : 2}, { "scale" : 73957190.948944, "resolution" : 19567.87924099992, "level" : 3}, { "scale" : 36978595.474472, "resolution" : 9783.93962049996, "level" : 4}, { "scale" : 18489297.737236, "resolution" : 4891.96981024998, "level" : 5}, { "scale" : 9244648.868618, "resolution" : 2445.98490512499, "level" : 6}, { "scale" : 4622324.434309, "разрешение" : 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, "разрешение" : 38.21851414253662, "level" : 12}, { "scale" : 72223.819286, "resolution" : 19.109257071 26831, "level" : 13}, { "scale" : 36111.909643, "resolution" : 9.554628535634155, "level" : 14}, { "scale" : 18055.954822, "resolution" : 4.77731426794937, "level" : 15}, { "масштаб": 9027.977411, "разрешение" : 2.388657133974685, "уровень": 16}, { "масштаб": 4513.988705, "разрешение" : 1.1943285668550503, "уровень": 17}, { "шкала": 2256.994353, "разрешение" : 0,5971642835598172, "level" : 18}, { "scale" : 1128.497176, "resolution" : 0.29858214164761665, "level" : 19}, { "scale" : 564.248588, "resolution" : 0.14929107082380833, "level" : 20}, { "масштаб": 282.124294, "разрешение" : 0.07464553541190416, "уровень": 21}, { "шкала": 141.062147, "разрешение" : 0.03732276770595208, "уровень": 22}, { "масштаб": 70.5310735, "разрешение" : 0.01866138385297604, "level" : 23}]
- 24
- { "scale" : 70.5310735, "resolution" : 0.01866138385297604, "level" : 23}
Ответ 29
Если кто-то просто хочет извлечь значения из простых объектов 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
Ответ 30
Я не могу использовать ни один из ответов здесь. Нет доступных jq, никаких массивов оболочек, нет объявлений, нет grep -P, нет предвидения и предвидения, нет Python, нет Perl, нет Ruby, нет - даже нет Bash... Остальные ответы просто не работают хорошо. JavaScript звучит знакомо, но в банке написано Nescaffe - так что это тоже не пойдет :) Даже если таковые имеются, для моей простой необходимости - они будут излишними и медленными.
Тем не менее, для меня чрезвычайно важно получить много переменных из ответа моего модема в формате json. Я делаю это в sh с очень урезанным BusyBox на моих маршрутизаторах! Нет проблем с использованием только awk: просто установите разделители и прочитайте данные. Для одной переменной это все!
awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json
Помните, у меня нет массивов? Я должен был присвоить анализируемые в awk данные 11 переменным, которые мне нужны в сценарии оболочки. Куда бы я ни посмотрел, это считалось невыполнимой миссией. С этим тоже проблем нет.
Мое решение простое. Этот код будет: 1) анализировать файл .json из вопроса (на самом деле, я позаимствовал образец рабочих данных из наиболее часто задаваемого ответа) и выбрать данные в кавычках, плюс 2) создать переменные оболочки из awk, присваивая свободную именованную оболочку имена переменных.
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 сек.