我正在尝试解析从curl请求返回的JSON,如下所示:
卷曲’http://twitter.com/users/username.json'| sed -e’s / [{}] /’‘/ g’| awk -v k =“text”’{n = split($ 0,a,“,”); for(i = 1; i <= n; i + -
你问过如何用脚射击自己,我在这里提供弹药:
curl -s 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^text/ {print $2}'
你可以用 tr -d '{}' 代替 sed 。但完全抛弃它们似乎也会产生预期的效果。
tr -d '{}'
sed
如果要剥离外部引号,请将上述结果通过 sed 's/\(^"\|"$\)//g'
sed 's/\(^"\|"$\)//g'
我认为其他人已经发出足够的警报。我会站着用手机打电话给救护车。准备好时开火。
你可以试试这样的东西 -
curl -s 'http://twitter.com/users/jaypalsingh.json' | awk -F=":" -v RS="," '$1~/"text"/ {print}'
要快速提取特定键的值,我个人喜欢使用“grep -o”,它只返回正则表达式的匹配。例如,要从推文中获取“文本”字段,请执行以下操作:
grep -Po '"text":.*?[^\\]",' tweets.json
这个正则表达式比你想象的更强大;例如,它可以很好地处理嵌入了逗号并在其中包含转义引号的字符串。我认为通过更多的工作,你可以制作一个实际上可以保证提取值,如果它是原子的。 (如果它有嵌套,那么正则表达式当然不能这样做。)
要进一步清理(尽管保持字符串的原始转义),您可以使用以下内容: | perl -pe 's/"text"://; s/^"//; s/",$//' 。 (我这样做了 这个分析 。)
| perl -pe 's/"text"://; s/^"//; s/",$//'
对于所有坚持你的仇敌应该使用真正的JSON解析器 - 是的,这对正确性至关重要,但是
grep -o
json
要编写可维护的代码,我总是使用真正的解析库。我没试过 jsawk ,但如果它运作良好,那将解决点#1。
最后一个更糟糕的解决方案:我编写了一个使用Python的脚本 json 并将所需的键提取到制表符分隔的列中;然后我穿过一个包装纸 awk 允许对列进行命名访问。 在这里:json2tsv和tsvawk脚本 。所以对于这个例子,它将是:
awk
json2tsv id text < tweets.json | tsvawk '{print "tweet " $id " is: " $text}'
这种方法没有解决#2问题,比单个Python脚本效率更低,而且有点脆弱:它强制对字符串值中的换行符和制表符进行规范化,以便与awk的字段/记录分隔的世界视图一起使用。但它确实让你留在命令行,更正确 grep -o 。
TickTick 是一个用bash编写的JSON解析器(&lt; 250行代码)
这是作者的文章中的snippit, 想象一下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
这是一个很好的参考 。在这种情况下:
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++) { where = match(a[i], /\"text\"/); if(where) {print a[i]} } }'
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
使用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]);"
如果有人只想从简单的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
您可以使用 jshon :
jshon
curl 'http://twitter.com/users/username.json' | jshon -e text
这是你用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 } } }'
基于这里的一些建议(特别是在评论中)建议使用Python,我很失望没有找到一个例子。
所以,这里有一个单行程序来从一些JSON数据中获取单个值。它假设您正在(从某处)管道数据,因此在脚本环境中应该是有用的。
echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hostname"]'
使用 Python的JSON支持 而不是使用awk!
像这样的东西:
curl -s http://twitter.com/users/username.json | \ python -c "import json,sys;obj=json.load(sys.stdin);print obj['name'];"
也有xml文件的人可能想看看我的 Xidel 。这是一个cli,无依赖性 JSONiq 处理器。 (即它还支持XQuery for xml或json处理)
问题中的例子是:
xidel -e 'json("http://twitter.com/users/username.json")("name")'
或者使用我自己的非标准扩展语法:
xidel -e 'json("http://twitter.com/users/username.json").name'
继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
解析JSON在shell脚本中很痛苦。使用更合适的语言,创建一个以与shell脚本约定一致的方式提取JSON属性的工具。您可以使用新工具解决即时shell脚本问题,然后将其添加到您的工具包中以备将来使用。
例如,考虑一个工具 jsonlookup 如果我说的话 jsonlookup access token id 它将返回属性 ID 在属性中定义 代币 在属性中定义 访问 来自stdin,这可能是JSON数据。如果该属性不存在,则该工具不返回任何内容(退出状态1)。如果解析失败,请退出状态2并向stderr发送消息。如果查找成功,该工具将打印属性的值。
jsonlookup access token id
为了提取JSON值的精确目的创建了一个unix工具,您可以在shell脚本中轻松使用它:
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
我不能在这里使用任何答案。没有可用的jq,没有shell数组,没有声明,没有grep -P,没有lookbehind和lookahead,没有Python,没有Perl,没有Ruby,没有 - 甚至没有Bash ......剩下的答案根本就不能正常工作。 JavaScript听起来很熟悉,但是锡说Nescaffe - 所以它也是不行的:)即使可用,为了我的简单需要 - 它们会有点过分和缓慢。
然而,对我来说,从我的调制解调器的json格式回复中获取许多变量是非常重要的。我正在我的路由器中使用非常精简的BusyBox进行操作!单独使用awk没问题:只需设置分隔符并读取数据。对于单个变量,这就是全部!
awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json
还记得我没有阵列吗?我必须在awk解析数据中分配我在shell脚本中需要的11个变量。无论我在哪里,据说这是一项不可能完成的任务。也没问题。
我的解决方案很简单。此代码将: 1)解析问题中的.json文件(实际上,我从最热门的答案中借用了一个工作数据样本)并选出引用的数据,加上 2)从awk中创建shell变量,分配自由命名的shell变量名。
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来实现边际速度增益。缺乏阵列显然意味着:没有多余的记录而没有额外的摆弄。但是在阵列可用的情况下,调整此解决方案是一项简单的任务。
@maikel sed答案几乎可行(但我无法评论)。对于我格式很好的数据 - 它的工作原理。与此处使用的示例不同(缺少引号将其抛弃)。它很复杂,很难修改。另外,我不喜欢打11次调用来提取11个变量。为什么?我定时100个循环提取9个变量:sed函数花了48.99秒,我的解决方案花了0.91秒!不公平?只需提取9个变量:0.51对0.02秒。
使用python的双线程。如果您正在编写单个.sh文件并且不想依赖另一个.py文件,那么它的效果尤其好。它还利用了管道的使用 | 。 echo "{\"field\": \"value\"}" 可以用任何打印json到stdout的东西代替。
|
echo "{\"field\": \"value\"}"
echo "{\"field\": \"value\"}" | python -c 'import sys, json print(json.load(sys.stdin)["field"])'
如果 pip 然后在系统上可用:
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