Я пытаюсь проанализировать 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
)?
grep -Po '"'"version"'"\s*:\s*"\K([^"]*)' package.json
, Это решает задачу легко и только с помощью grep и отлично работает для простых JSON. Для сложных JSON вы должны использовать правильный парсер.Ответы:
Существует ряд инструментов, специально разработанных для манипулирования JSON из командной строки, и будет намного проще и надежнее, чем с Awk, например
jq
:Вы также можете сделать это с помощью инструментов, которые, вероятно, уже установлены в вашей системе, например, Python, использующий
json
модуль , и, таким образом, избежать каких-либо дополнительных зависимостей, сохраняя при этом преимущество правильного анализатора JSON. Далее предполагается, что вы хотите использовать UTF-8, в который должен быть закодирован исходный JSON и который также используется большинством современных терминалов:Python 3:
Python 2:
Исторические заметки
Первоначально этот ответ рекомендовал jsawk , который все еще должен работать, но его использование несколько сложнее
jq
и зависит от устанавливаемого автономного интерпретатора JavaScript, который менее распространен, чем интерпретатор Python, поэтому приведенные выше ответы, вероятно, предпочтительнее:В этом ответе также изначально использовался API-интерфейс Twitter из этого вопроса, но этот API-интерфейс больше не работает, что затрудняет копирование примеров для тестирования, а новому API-интерфейсу Twitter требуются ключи API, поэтому я перешел к использованию GitHub API, который можно легко использовать без ключей API. Первый ответ на оригинальный вопрос будет:
источник
print
оператор всегда будет кодироваться в ASCII, потому что вы используете Python в конвейере. ВставьтеPYTHONIOENCODING=<desired codec>
в команду, чтобы установить другую выходную кодировку, подходящую для вашего терминала. В Python 3 значением по умолчанию является UTF-8 в этом случае (с использованиемprint()
функции ).curl -s
эквивалентноcurl --silent
, тогда какjq -r
означает,jq --raw-output
то есть без строковых кавычек.Чтобы быстро извлечь значения для определенного ключа, мне лично нравится использовать «grep -o», который возвращает только совпадение с регулярным выражением. Например, чтобы получить поле «текст» из твитов, что-то вроде:
Это регулярное выражение более надежно, чем вы думаете; например, он прекрасно работает со строками, в которых есть запятые и экранированные кавычки. Я думаю, немного проделав работу, вы могли бы сделать такую, которая действительно гарантированно извлечет значение, если оно атомарное. (Если у него есть вложенность, то регулярное выражение не может сделать это, конечно.)
И дальнейшие чистый (хотя и сохраняя первоначальное вытекание струны) , вы можете использовать что - то вроде:
| perl -pe 's/"text"://; s/^"//; s/",$//'
. (Я сделал это для этого анализа .)Всем ненавистникам, которые настаивают на том, что вы должны использовать настоящий анализатор JSON - да, это важно для правильности, но
grep -o
на несколько порядков быстрее, чем стандартнаяjson
библиотека Python , по крайней мере при выполнении этого для твитов (каждый из которых составляет ~ 2 КБ). Я не уверен, что это только потому, чтоjson
это медленно (я должен сравнить с yajl когда-нибудь); но в принципе регулярное выражение должно быть быстрее, поскольку оно имеет конечное состояние и гораздо более оптимизируемое, а не синтаксический анализатор, который должен поддерживать рекурсию, и в этом случае тратит много деревьев построения ЦП для структур, которые вас не интересуют. (Если бы кто-то написал преобразователь конечного состояния, который выполнял правильный (ограниченный по глубине) анализ JSON, это было бы здорово! Тем временем у нас есть «grep -o».)Для написания поддерживаемого кода я всегда использую настоящую библиотеку синтаксического анализа. Я не пробовал jsawk , но если он будет работать хорошо, это будет точка № 1.
Последнее, более странное решение: я написал скрипт, который использует Python
json
и извлекает нужные ключи в столбцы, разделенные табуляцией; затем я передаю через обертку,awk
которая позволяет именованный доступ к столбцам. Здесь: сценарии json2tsv и tsvawk . Так что для этого примера это будет:Этот подход не относится к # 2, он более неэффективен, чем отдельный скрипт Python, и он немного хрупок: он заставляет нормализовать переводы строк и табуляции в строковых значениях, чтобы хорошо сочетаться с представлением awk в поле / записи с разделением по полю мира. Но это позволяет вам оставаться в командной строке с большей точностью, чем
grep -o
.источник
grep -Po '"text":(\d*?,|.*?[^\\]",)'
jq .name
работает в командной строке и не требует «открытия редактора для написания скрипта». 2. Неважно, как быстро ваше регулярное выражение может давать неправильные результаты| grep -Po '"text":.*?[^\\]",'|awk -F':' '{print $2}'
-P
опция отсутствует. Я тестировал на OSX 10.11.5 иgrep --version
былgrep (BSD grep) 2.5.1-FreeBSD
. Я получил его работать с опцией "расширенное регулярное выражение" на OSX. Команда сверху была быgrep -Eo '"text":.*?[^\\]",' tweets.json
.На основании того, что некоторые из рекомендаций здесь (особенно в комментариях) предполагают использование Python, я был разочарован тем, что не нашел пример.
Итак, вот один вкладыш для получения одного значения из некоторых данных JSON. Предполагается, что вы отправляете данные (откуда-то) и поэтому должны быть полезны в контексте сценариев.
источник
pythonpy
( github.com/russell91/pythonpy почти всегда является лучшей альтернативойpython -c
, хотя он должен быть установлен с помощью pip. просто направьте json наpy --ji -x 'x[0]["hostname"]'
. Если вы не хотите использовать встроенную поддержку json_input, вы все равно можете получить эти импортируются автоматически какpy 'json.loads(sys.stdin)[0]["hostname"]'
jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); print($1)"; }
чтобы я мог написать:curl ...... | jsonq 'json.dumps([key["token"] for key in obj], indent=2)'
и другие подобные страшные вещи ... Кстати,obj[0]
кажется ненужным, похоже, что онobj
работает нормально в случаях по умолчанию (?).jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); sys.stdout.write(json.dumps($1))"; }
obj[0]
вызывает ошибку при разборе{ "port":5555 }
. Работает нормально после удаления[0]
.Следуя примеру MartinR и Boecko:
Это даст вам чрезвычайно дружественный вывод grep. Очень удобно:
источник
| grep field
. Спасибо!jq
обычно не устанавливается в то время как Python. Кроме того, попав в Python, вы можете пройти весь путь и проанализировать егоimport json...
Вы можете просто загрузить
jq
бинарный файл для вашей платформы и запустить (chmod +x jq
):Он извлекает
"name"
атрибут из объекта json.jq
домашняя страница говорит, что это какsed
для данных JSON.источник
jq
это удивительный инструмент.curl -s https://api.example.com/jobs | jq '.jobs[] | {id, o: .owner.username, dateCreated, s: .status.state}'
Использование Node.js
Если система имеет узелпосле установки можно использовать флаги сценария
-p
print и-e
evaulate,JSON.parse
чтобы извлечь любое необходимое значение.Простой пример использования строки JSON
{ "foo": "bar" }
и извлечения значения «foo»:Поскольку у нас есть доступ
cat
и другие утилиты, мы можем использовать это для файлов:Или любой другой формат, такой как URL, который содержит JSON:
источник
node -p -e 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
curl -s https://api.github.com/users/trevorsenior | node -pe "JSON.parse(require('fs').readFileSync('/dev/stdin').toString()).name"
cat package.json | node -pe 'JSON.parse(fs.readFileSync(0)).version'
Используйте поддержку Python JSON вместо awk!
Что-то вроде этого:
источник
json.load(sys.stdin)['"key']"
качестве примера , как:curl -sL httpbin.org/ip | python -c "import json,sys; print json.load(sys.stdin)['origin']"
.Вы спросили, как выстрелить себе в ногу, и я здесь, чтобы предоставить боеприпасы:
Вы могли бы использовать
tr -d '{}'
вместоsed
. Но полное их исключение, похоже, также дает желаемый эффект.Если вы хотите удалить внешние кавычки, передайте результат вышеупомянутого через
sed 's/\(^"\|"$\)//g'
Я думаю, что другие забили достаточно тревоги. Я буду стоять с сотовым телефоном, чтобы вызвать скорую помощь. Огонь, когда будете готовы.
источник
Использование Bash с Python
Создайте функцию bash в вашем файле .bash_rc
затем
Здесь та же функция, но с проверкой ошибок.
Где $ # -ne 1 гарантирует, что хотя бы 1 ввод, а -t 0 - перенаправление из канала.
Приятной особенностью этой реализации является то, что вы можете получить доступ к вложенным значениям json и получить взамен json! знак равно
Пример:
Если вы хотите быть по-настоящему модным, можете распечатать данные:
источник
curl http://foo | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["environment"][0]["name"]'
sys.stdout.write()
если вы хотите, чтобы он работал с Python 2 и 3.getJsonVal() { py -x "json.dumps(json.loads(x)$1, sort_keys=True, indent=4)"; }
TickTick - это анализатор JSON, написанный на bash (<250 строк кода)
Вот отрывок из его статьи « Представьте мир, в котором Bash поддерживает JSON» :
источник
Разбор JSON с PHP CLI
Возможно, не по теме, но, поскольку царит приоритет, этот вопрос остается неполным без упоминания нашего верного и верного PHP, я прав?
Используя тот же пример JSON, но давайте присвоим его переменной, чтобы уменьшить затенение.
Теперь для бога PHP, используя file_get_contents и обертку потока php: // stdin .
или, как указано, используя fgets и уже открытый поток с константой CLI STDIN .
NJoy!
источник
$argn
вместоfgets(STDIN)
$argn
работает с флагом -E или -R и только если содержимое JSON находится в одной строке ...Родная версия Bash: также хорошо работает с обратной косой чертой (\) и кавычками (")
источник
Версия, которая использует Ruby и http://flori.github.com/json/
или более кратко:
источник
;
не требуется в Ruby (он используется только для объединения операторов, которые обычно бывают отдельными строками в одну строку).К сожалению, топ проголосовали ответ , который использует
grep
возвращает полный матч , который не работал в моем сценарии, но если вы знаете формат JSON будет оставаться постоянной вы можете использовать назад ' и предпросмотр для извлечения только требуемых значений.источник
Если кто-то просто хочет извлечь значения из простых объектов JSON без вложенных структур, можно использовать регулярные выражения, даже не выходя из bash.
Вот функция, которую я определил, используя регулярные выражения bash на основе стандарта JSON :
Предостережения: объекты и массивы не поддерживаются как значения, но поддерживаются все другие типы значений, определенные в стандарте. Кроме того, пара будет сопоставляться независимо от того, насколько глубоко она находится в документе JSON, если она имеет абсолютно одинаковое имя ключа.
Используя пример OP:
источник
Есть более простой способ получить свойство из строки json. Используя
package.json
файл в качестве примера, попробуйте это:Мы используем его,
process.env
потому что он передает содержимое файла в node.js в виде строки без риска того, что вредоносное содержимое выйдет из их цитирования и будет проанализировано как код.источник
require()
самом деле может запускать чужой код, JSON.parse не может.JSON.parse()
и да, вы однозначно в безопасности ... но здесь среда выполнения JSON получает (ненадежное) содержимое внутри полосы с (доверенным) кодом.JSON.parse()
, вы тоже в безопасности, но здесь этого тоже не происходит.JSON.parse()
в код переменную оболочки, которую вы собираетесь передать . Вы предполагаете, что размещение буквенных обратных кавычек сохранит содержимое буквальным, но это совершенно небезопасное предположение, потому что буквальные обратные кавычки могут существовать в содержимом файла (и, следовательно, в переменной), и, таким образом, могут завершать цитирование и вводить контекст без кавычек, где значения выполняются как код.Теперь, когда Powershell является кроссплатформенным, я подумал, что смогу найти выход из положения, поскольку считаю его довольно интуитивным и чрезвычайно простым.
ConvertFrom-Json преобразует JSON в пользовательский объект Powershell, поэтому вы можете легко работать со свойствами с этого момента. Например, если вам нужно только свойство id, вы просто сделаете это:
Если вы хотите вызвать все это изнутри Bash, то вам придется называть это так:
Конечно, есть чистый способ Powershell сделать это без curl, который будет:
Наконец, есть также ConvertTo-Json, который так же легко преобразует пользовательский объект в JSON. Вот пример:
Что дало бы хороший JSON вот так:
}
По общему признанию, использование оболочки Windows в Unix несколько кощунственно, но Powershell действительно хорош в некоторых вещах, и разбор JSON и XML - пара из них. Эта страница GitHub для кросс-платформенной версии https://github.com/PowerShell/PowerShell
источник
Кто-то, у кого также есть XML-файлы, может захотеть взглянуть на мой Xidel . Это cli, не зависящий от JSONiq процессор. (т.е. он также поддерживает XQuery для обработки XML или JSON)
Пример в вопросе будет:
Или с моим собственным нестандартным синтаксисом расширения:
источник
xidel -s https://api.github.com/users/lambda -e 'name'
(или-e '$json/name'
, или-e '($json).name'
).Я не могу использовать ни один из ответов здесь. Нет доступных jq, нет массивов оболочек, нет объявлений, нет grep -P, нет look -hind и lookahead, нет Python, нет Perl, нет Ruby, нет - даже нет Bash ... Остальные ответы просто не работают хорошо. JavaScript звучит знакомо, но в банке написано Nescaffe - так что это тоже не пойдет :) Даже если таковые имеются, для моей простой необходимости - они будут излишними и медленными.
Тем не менее, для меня чрезвычайно важно получить много переменных из ответа моего модема в формате json. Я делаю это в sh с очень урезанным BusyBox на моих маршрутизаторах! Нет проблем с использованием только awk: просто установите разделители и прочитайте данные. Для одной переменной это все!
Помните, у меня нет массивов? Я должен был присвоить анализируемые в awk данные 11 переменным, которые мне нужны в сценарии оболочки. Куда бы я ни посмотрел, это считалось невыполнимой миссией. С этим тоже проблем нет.
Мое решение простое. Этот код будет: 1) анализировать файл .json из вопроса (на самом деле, я позаимствовал образец рабочих данных из наиболее часто задаваемого ответа) и выбрать данные в кавычках, плюс 2) создать переменные оболочки из awk, присваивая свободную именованную оболочку имена переменных.
Никаких проблем с пробелами внутри. В моем случае эта же команда анализирует длинный однострочный вывод. Поскольку используется eval, это решение подходит только для доверенных данных. Его легко адаптировать к данным без кавычек. Для огромного числа переменных, предельное увеличение скорости может быть достигнуто с помощью else if. Отсутствие массива, очевидно, означает: нет нескольких записей без лишних действий. Но там, где имеются массивы, адаптация этого решения - простая задача.
Ответ @maikel sed почти работает (но я не могу это комментировать). Для моих красиво отформатированных данных - это работает. Не так много с примером, использованным здесь (пропущенные кавычки отбрасывают его). Это сложно и сложно изменить. Кроме того, мне не нравится делать 11 вызовов для извлечения 11 переменных. Почему? Я рассчитал 100 циклов, извлекая 9 переменных: функция sed заняла 48,99 с, а мое решение заняло 0,91 с! Не честно? Выполнение только одного извлечения из 9 переменных: 0,51 против 0,02 сек.
источник
Вы можете попробовать что-то вроде этого -
источник
Вы можете использовать
jshon
:источник
вот один из способов сделать это с помощью awk
источник
Для более сложного анализа JSON я предлагаю использовать модуль jsonpath python (автор Stefan Goessner) -
sudo easy_install -U jsonpath
Пример file.json (из http://goessner.net/articles/JsonPath ) -
Разобрать его (извлечь все названия книг с ценой <10) -
Будет выходной -
ПРИМЕЧАНИЕ. Приведенная выше командная строка не включает проверку ошибок. для полного решения с проверкой ошибок вы должны создать небольшой скрипт на python и обернуть код в try-exc.
источник
jsonpath
так установленногоjsonpath_rw
вместо этого, поэтому вот что-то похожее, что вы можете попробовать, если вышеописанное не работает: 1)/usr/bin/python -m pip install jsonpath-rw
2)cat ~/trash/file.json | /usr/bin/python -c "from jsonpath_rw import jsonpath, parse; import sys,json; jsonpath_expr = parse('store.book[0]'); out = [match.value for match in jsonpath_expr.find(json.load(sys.stdin))]; print out;"
(Я использовал полный путь к двоичному файлу python, потому что у меня были некоторые проблемы с несколькими питонами установлены).Если у вас есть php :
Например:
у нас есть ресурс, который предоставляет json коды iso стран: http://country.io/iso3.json, и мы легко можем увидеть его в оболочке с curl:
но выглядит не очень удобно и не читабельно, лучше разбирать json и видеть читаемую структуру:
Этот код напечатает что-то вроде:
если у вас есть вложенные массивы, этот вывод будет выглядеть намного лучше ...
Надеюсь, это будет полезно ...
источник
Существует также очень простой , но мощный JSON CLI обработки инструмент FX - https://github.com/antonmedv/fx
Примеры
Используйте анонимную функцию:
Если вы не передадите анонимную функцию param => ..., код будет автоматически преобразован в анонимную функцию. И вы можете получить доступ к JSON по этому ключевому слову:
Или просто используйте точечный синтаксис:
Вы можете передать любое количество анонимных функций для сокращения JSON:
Вы можете обновить существующий JSON с помощью оператора распространения:
Просто простой JavaScript . Не нужно изучать новый синтаксис.
ОБНОВЛЕНИЕ 2018-11-06
fx
теперь есть интерактивный режим ( ! )https://github.com/antonmedv/fx
источник
Это еще один
bash
иpython
гибридный ответ. Я опубликовал этот ответ, потому что хотел обработать более сложный вывод JSON, но, уменьшив сложность моего приложения bash. Я хочу взломать следующий объект JSON с http://www.arcgis.com/sharing/rest/info?f=json вbash
:В следующем примере я создал свою собственную реализацию
jq
иunquote
использованиеpython
. Вы заметите, что как только мы импортируем объект python изjson
словаря python, мы можем использовать синтаксис python для навигации по словарю. Для навигации выше, синтаксис:data
data[ "authInfo" ]
data[ "authInfo" ][ "tokenServicesUrl" ]
Используя магию в bash, мы опускаем
data
и поставляем только текст на Python справа от данных, т.е.jq
jq '[ "authInfo" ]'
jq '[ "authInfo" ][ "tokenServicesUrl" ]'
Обратите внимание, без параметров,
jq
действует как префиксатор JSON. С помощью параметров мы можем использовать синтаксис Python для извлечения из словаря всего, что нам нужно, включая навигацию по поддиректориям и элементам массива.Вот рабочий пример, демонстрирующий вышесказанное:
источник
Я сделал это, "проанализировав" ответ json для определенного значения, следующим образом:
Ясно, что $ url здесь будет URL-адресом твиттера, а $ var будет «текстом», чтобы получить ответ для этой переменной.
На самом деле, я думаю, что единственное, что я делаю в OP, это grep для строки с конкретной переменной, которую он ищет. Awk берет второй элемент в строке, и с помощью sed я убираю цитаты.
Кто-то умнее меня, вероятно, мог бы все мыслить с помощью awk или grep.
Теперь вы можете сделать все это с помощью sed:
таким образом, нет awk, нет grep ... Я не знаю, почему я не думал об этом раньше. Хммм ...
источник
grep | awk | sed
Иsed | sed | sed
трубопроводы расточительных antipatterns. Ваш последний пример можно легко переписать,curl "$url" | sed '/text/!d;s/\"text\"://g;s/\"//g;s/\ //g'
но, как уже отмечали другие, это подверженный ошибкам и хрупкий подход, который не следует рекомендовать в первую очередь.Разбор JSON является болезненным в сценарии оболочки. Используя более подходящий язык, создайте инструмент, который извлекает атрибуты JSON способом, соответствующим соглашениям сценариев оболочки. Вы можете использовать свой новый инструмент, чтобы решить непосредственную проблему сценариев оболочки, а затем добавить его в свой комплект для будущих ситуаций.
Например, рассмотрим инструмент jsonlookup , который, если я скажу
jsonlookup access token id
, вернет идентификатор атрибута, определенный в маркере атрибута, определенном в атрибуте access из stdin, который предположительно представляет собой данные JSON. Если атрибут не существует, инструмент ничего не возвращает (состояние выхода 1). Если синтаксический анализ завершился неудачно, выйдите из состояния 2 и отправьте сообщение в stderr. Если поиск успешен, инструмент печатает значение атрибута.Создав инструмент Unix для точной цели извлечения значений JSON, вы можете легко использовать его в сценариях оболочки:
Любой язык подойдет для реализации jsonlookup . Вот довольно лаконичная версия Python:
источник
Двухслойный, который использует Python. Это особенно хорошо работает, если вы пишете один файл .sh и не хотите зависеть от другого файла .py. Это также использует использование трубы
|
.echo "{\"field\": \"value\"}"
может быть заменено на что-либо, печатающее JSON на стандартный вывод.источник
Это хороший пример использования Pythonpy :
источник