我试图解析从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=文本表示)?


当前回答

在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

其他回答

还有一个非常简单但功能强大的JSON CLI处理工具fx。

例子

使用匿名函数:

echo '{"key": "value"}' | fx "x => x.key"

输出:

value

如果你不传递匿名函数参数→…,代码将自动转换为匿名函数。你可以通过这个关键字访问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。没有必要学习新的语法。


fx的后期版本有一个互动模式!-

使用node . js

如果系统安装了Node.js,则可以在JSON中使用-p print和-e evaluate脚本标志。解析以提取所需的任何值。

一个简单的例子,使用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

或包含JSON的URL等任何其他格式:

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

输出:

Trevor Senior

为了快速提取特定键的值,我个人喜欢使用“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更正确。

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

下面是shell书呆子使用POSIX shell(带local)和egrep的答案:JSON.sh, 4.7 KB。

这个东西有很多测试用例,所以它应该是正确的。它也是可管道的。它用于Bash的包管理器bpkg。