Синтаксический анализ JSON с помощью инструментов Unix

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

curl 'http://twitter.com/users/username.json' |
    sed -e 's/[{}]/''/g' | 
    awk -v k="text" '{n=split(,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)?

30 ответов


существует ряд инструментов, специально разработанных для манипулирования 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 GitHub, который можно легко использовать без ключей API. Первым ответом на первоначальный вопрос будет:

curl 'http://twitter.com/users/username.json' | jq -r '.text'

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

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

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

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

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

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

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

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

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

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


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

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

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

следующим MartinR и Boecko ведущий:

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

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

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

вы могли бы просто скачать jq binary для вашей платформы и (chmod +x jq):

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

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

jq Домашняя страница говорит, что это нравится sed для данных JSON.


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

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

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

Через Узел.js

если система имеет узел установлен, можно использовать -p печать -e evaulate флаги сценария с 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

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

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

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

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

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


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

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

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

затем

$ 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)))";
}

где $ # - 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), sort_keys=True, indent=4))"; 
}

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

разбор 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;'

кафе!


TickTick - парсер JSON, написанный на bash (

вот отрывок автора из его статьи,представьте себе мир, где 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

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

function parse_json()
{
    echo  | \
    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~/\"\"/ {print}" | \
    sed -e "s/\"\"://" | \
    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":"john@doe.com"}' username
parse_json '{"username":"john doe","email":"john@doe.com"}' email

--- outputs ---

john, doe
johh@doe.com

версия, которая использует 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]);"

можно использовать jshon:

curl 'http://twitter.com/users/username.json' | jshon -e text

к сожалению, верхний проголосовал ответ, который использует 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

вот один из способов сделать это с 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
        }
    }
}'

кто-то, у кого также есть 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'

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

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

sudo easy_install-U jsonpath

  1. использовать его -

пример файла.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
    }
  }
}

разберите его (извлеките все названия книг с ценой

$ 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-except.


если у вас php:

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

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

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',
  ...

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

надеюсь, это будет полезно...


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

curl -s 'http://twitter.com/users/jaypalsingh.json' | 
awk -F=":" -v RS="," '~/"text"/ {print}'

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

например, рассмотрим инструмент jsonlookup такое, что если я говорю jsonlookup access token id он вернет атрибут id определено в атрибуте маркер определено в атрибуте открыть из 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

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

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

Это хороший usecase для pythonpy:

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

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

теперь, когда 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


это еще один 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="''"
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

выход выше скрипт:

I добавлена поддержка массивов, поэтому вы можете использовать .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
  • [{"данные": 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}, {"данные": 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}, {"данные": 577790.554289, "разрешение": 152.87405657041106, "уровень": 10}, {"масштаб": 288895.277144, "разрешение": 76.43702828507324, "Уровень": 11}, {"масштаб": 144447.638572, "разрешение": 38.21851414253662, "Уровень": 12}, {"масштаб": 72223.819286, "разрешение": 19.10925707126831, "Уровень": 13}, {"масштаб": 36111.909643, "разрешение": 9.554628535634155, "уровень": 14}, {"масштаб": 18055.954822, "разрешение": 4.77731426794937, "уровень": 15}, {"масштаб": 9027.977411, "разрешение": 2.388657133974685," уровень": 16}, {"масштаб": 4513.988705, "разрешение": 1.1943285668550503, "уровень": 17}, {"масштаб": 2256.994353, "разрешение": 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
  • {"масштаб": 70.5310735, "разрешение": 0.01866138385297604, "уровень": 23}

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

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

function json_extract() {
  local key=
  local json=

  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

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

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

Ниет это инструмент, который поможет вам извлечь данные из файла JSON или yaml непосредственно в вашей оболочке/bash CLI.

$ 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

я использовал это для извлечения длительности видео из вывода 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