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


当前回答

有一种更简单的方法可以从JSON字符串中获取属性。使用包。Json文件作为一个例子,试试这个:

#!/usr/bin/env bash
my_val="$(json=$(<package.json) node -pe "JSON.parse(process.env.json)['version']")"

我们使用的是过程。env,因为这会将文件的内容作为字符串放入Node.js,而不会有恶意内容逃脱引用并被解析为代码的风险。

其他回答

这里有一种使用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
        }
    }
}'

你可以使用jshon:

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

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

你可以尝试这样做-

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

这里我不能用任何答案。jq、shell数组、声明、grep -P、后视、前视、Python、Perl、Ruby甚至Bash都不可用。

剩下的答案都不太管用。JavaScript听起来很熟悉,但罐头上写的是Nescaffe——所以也不行:)即使有,对于我的简单需求——它们也会过度消耗和缓慢。

然而,对我来说,从我的调制解调器的JSON格式的回复中获得许多变量是极其重要的。我在Bourne shell (sh)做它与一个非常修剪下来的BusyBox在我的路由器!单独使用AWK没有任何问题:只需设置分隔符并读取数据。对于单个变量,这就是全部!

awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json

还记得我没有数组吗?我必须在AWK解析数据中分配给我在shell脚本中需要的11个变量。我所到之处,都有人说这是不可能完成的任务。这也没有问题。

我的解决办法很简单。这段代码将:

parse .json file from the question (actually, I have borrowed a working data sample from the most upvoted answer) and picked out the quoted data, plus create shell variables from within the awk assigning free named shell variable names. 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 if实现边际速度增益。缺乏数组显然意味着:没有额外的操作就没有多个记录。但是在数组可用的情况下,调整这个解决方案是一项简单的任务。

@maikel的sed回答几乎是有效的(但我不能评论它)。对于我的格式化好的数据-它工作。这里使用的例子没有太多(缺少引号)。它很复杂,很难修改。另外,我不喜欢进行11次调用来提取11个变量。为什么?我计时100循环提取9个变量:sed函数花了48.99秒,我的解决方案花了0.91秒!不公平?只提取9个变量:0.51秒vs. 0.02秒。