我试图解析从curl请求返回的JSON,就像这样:

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=文本表示)?


当前回答

YAML处理器yq

考虑使用yq进行JSON处理。 yq是一个轻量级、可移植的命令行YAML处理器(JSON是YAML的一个子集)。 语法类似于jq。

输入

{
  "name": "Angel",
  "address": {
    "street": "Stairway to",
    "city": "Heaven"
  }
}

用法举例1

yq e ` .name ` $FILE

Angel

用法举例二

yq有一个很好的内置特性,可以使JSON和YAML成为grep-able

yq——输出格式道具$FILE

name = Angel
address.street = Stairway to
address.city = Heaven

其他回答

既然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"
             ]

}

诚然,在Unix上使用Windows shell有点亵渎神明,但PowerShell确实擅长某些事情,解析JSON和XML就是其中之一。这是跨平台版本PowerShell的GitHub页面

为了快速提取特定键的值,我个人喜欢使用“grep -o”,它只返回正则表达式的匹配项。例如,要从tweets中获取“text”字段,如下所示:

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

这个正则表达式比你想象的更健壮;例如,它可以很好地处理包含逗号和转义引号的字符串。我想再做点工作,你就能做出一个保证能提取值的程序,如果它是原子的。(如果它有嵌套,那么正则表达式当然不能这样做。)

为了进一步清除(尽管保持字符串的原始转义),您可以使用如下代码:| perl -pe 's/"text"://;/ / s / ^”;s /, / /美元”。(我这样做是为了分析。)

对于那些坚持认为你应该使用真正的JSON解析器的人——是的,这对于正确性是必不可少的,但是

To do a really quick analysis, like counting values to check on data cleaning bugs or get a general feel for the data, banging out something on the command line is faster. Opening an editor to write a script is distracting. grep -o is orders of magnitude faster than the Python standard json library, at least when doing this for tweets (which are ~2 KB each). I'm not sure if this is just because json is slow (I should compare to yajl sometime); but in principle, a regex should be faster since it's finite state and much more optimizable, instead of a parser that has to support recursion, and in this case, spends lots of CPU building trees for structures you don't care about. (If someone wrote a finite state transducer that did proper (depth-limited) JSON parsing, that would be fantastic! In the meantime we have "grep -o".)

为了编写可维护的代码,我总是使用真正的解析库。我还没有尝试过jsawk,但如果它工作得很好,这将解决第1点。

最后一个更古怪的解决方案:我写了一个脚本,使用Python json并将你想要的键提取到制表符分隔的列中;然后我通过awk的包装器,允许对列进行命名访问。这里:json2tsv和tsvawk脚本。对于这个例子,它将是:

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

这种方法没有解决第2点,比单一的Python脚本效率更低,而且有点脆弱:它强制将字符串值中的换行符和制表符规范化,以更好地处理awk的字段/记录分隔视图。但它确实让您停留在命令行上,比grep -o更正确。

Niet是一个工具,可以帮助您直接在shell或Bash CLI中从JSON或YAML文件中提取数据。

pip install niet

考虑一个名为project的JSON文件。Json,包含以下内容:

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

你可以这样使用Niet:

PROJECT_NAME=$(niet project.json project.meta.name)
echo ${PROJECT_NAME}

输出:

project-sample

在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

使用Python使用Bash

在.bashrc文件中创建一个Bash函数:

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

Then

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确保至少有一个输入,而-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"
}