题 如何在(Unix)shell脚本中打印JSON?


是否有(Unix)shell脚本以人类可读的形式格式化JSON?

基本上,我希望它改变以下内容:

{ "foo": "lorem", "bar": "ipsum" }

...进入这样的事情:

{
    "foo": "lorem",
    "bar": "ipsum"
}

2503


起源


stackoverflow.com/a/12892039/998291 - shleim
片刻之后我自己动了一下: github.com/exhuma/braindump/tree/master/jsonformat 代码非常简单,使用python自己的代码 json 库,但我添加了pygments以获得语法高亮。 - exhuma
偶然发现了这个,但后来发现了 Json Pretty 而且我非常喜欢它。 Typekit在他们的API示例中使用它,因此它背后有一些klout ^^ - Nick Tomlin
这是一篇博客文章,总结了本主题中提到的一些最佳方法。对于那些喜欢tldr的人: 链接 - PhilYoussef
被警告: python -m json.tool 并不总是生成有效的JSON。 (提示:1e1000) - peak


答案:


使用Python 2.6+,你可以做到:

echo '{"foo": "lorem", "bar": "ipsum"}' | python -m json.tool

或者,如果JSON在文件中,您可以:

python -m json.tool my_json.json

如果JSON来自互联网源,例如API,您可以使用

curl http://my_url/ | python -m json.tool

为了方便所有这些情况,您可以创建一个别名:

alias prettyjson='python -m json.tool'

为了更方便,更多的打字准备就绪:

prettyjson_s() {
    echo "$1" | python -m json.tool
}

prettyjson_f() {
    python -m json.tool "$1"
}

prettyjson_w() {
    curl "$1" | python -m json.tool
}

对于所有上述情况。你可以把它放进去 .bashrc 它每次都在shell中可用。像它一样调用它 prettyjson_s '{"foo": "lorem", "bar": "ipsum"}'


3740



你可以把它管道 pygmentize -l javascript 在命令行中获取语法彩色输出。 编辑:如果你安装了pygments,那就是。 - Shrikant Sharat
一个很好的答案,我唯一要注意的是它 不 在输出上对键进行排序 - 您可能需要注意这些键​​。 - Chris Nash
在myy .vimrc“nnoremap <f5>:%!python -m json.tool <CR>:w <CR>” - imwilsonxu
这似乎将Unicode字符转换为\ uXXXX,这可能是一个缺点。 - user1071136
我创建了一个别名: alias pretty='python -mjson.tool | pygmentize -l json 这样我才能跑: command params | pretty。希望这可以帮助。 PS:是否有人设法将此扩展到a)删除我每次都看到的卷曲输出和/或b)不对json键进行排序;请让我知道,我将非常感谢。 - Clint Eastwood


您可以使用: jq

它使用起来非常简单,效果很好!它可以处理非常大的JSON结构,包括流。你可以找到 他们的教程 这里

这是一个例子:

$ jq . <<< '{ "foo": "lorem", "bar": "ipsum" }'
{
  "bar": "ipsum",
  "foo": "lorem"
}

或者换句话说:

$ echo '{ "foo": "lorem", "bar": "ipsum" }' | jq .
{
  "bar": "ipsum",
  "foo": "lorem"
}

690



还有一个 --sort-keys 选项,这在某些情况下很有用。 - Matthew Flaschen
使用curl: curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.' - Hover Ruan
由于模糊不清,这个答案令人困惑 <<<运算符。为什么不用 echo '{ "foo": "lorem", "bar": "ipsum" }' | jq . 举个例子? - Meekohi
“jq。”作为一个漂亮的打印机是很棒的,但它有一个警告:jq(直到并包括jq版本1.5)将改变非常大和非常小的数字的值,因为它将数值解析为IEEE 754 64位值。要检查您最喜欢的漂亮打印机是否存在相同问题,请尝试以下值:1e1000。注意 python -mjson.tool 由于它产生Infinity,甚至不是JSON,因此严重失败了。 - peak
@Meekohi的替代方案是“不必要的使用回声”。超级高兴找到了 <<< 运营商 - 正是我想要的。 - jchook


我使用的是“空间”参数 JSON.stringify 在JavaScript中使用漂亮的JSON打印。

例子:

// Indent with 4 spaces
JSON.stringify({"foo":"lorem","bar":"ipsum"}, null, 4);

// Indent with tabs
JSON.stringify({"foo":"lorem","bar":"ipsum"}, null, '\t');

从带有nodejs的Unix命令行,在命令行上指定json:

$ node -e "console.log(JSON.stringify(JSON.parse(process.argv[1]), null, '\t'));" \
  '{"foo":"lorem","bar":"ipsum"}'

返回:

{
    "foo": "lorem",
    "bar": "ipsum"
}

从带有Node.js的Unix命令行,指定包含JSON的文件名,并使用四个空格的缩进:

$ node -e "console.log(JSON.stringify(JSON.parse(require('fs') \
      .readFileSync(process.argv[1])), null, 4));"  filename.json

使用管道:

echo '{"foo": "lorem", "bar": "ipsum"}' | node -e \
"\
 s=process.openStdin();\
 d=[];\
 s.on('data',function(c){\
   d.push(c);\
 });\
 s.on('end',function(){\
   console.log(JSON.stringify(JSON.parse(d.join('')),null,2));\
 });\
"

358



对于Node.js中的调试对象,您应该使用sys.inspect()而不是JSON.stringify()。原因如下: markhansen.co.nz/inspecting-with-json-stringify - Gurpartap Singh
Downvoted。 OP是关于“* nix命令行脚本”的,这个答案是不同的上下文。 - danorton
@danorton:JS可以通过node.js和其他类似的解决方案从命令行使用。 - calvinf
无需控制台: node -p "JSON.stringify(JSON.parse(process.argv[1]), null, '\t');" 还将结果输出到STDOUT。 - Julian D.
对于文件名与stdin的脚本不同,这很糟糕 - Lukasz Wiktor


我写了一个工具,它有一个最好的“智能空白”格式化器。它比这里的大多数其他选项产生更可读,更简洁的输出。

强调-CLI

这就是“智能空白”的样子:

我可能有点偏颇,但它是一个很棒的工具,用于从命令行打印和操作JSON数据。它使用起来非常友好,并提供广泛的命令行帮助/文档。这是一把瑞士军刀,我用它来完成1001个不同的小任务,任何其他方式都令人惊讶地烦人。

最新用例:Chrome,开发控制台,网络选项卡,全部导出为HAR文件,“cat site.har |下划线选择'.url' - outfmt text | grep mydomain”;现在我有一个按时间顺序列出的所有URL提取列表,在加载我公司的网站时。

漂亮的打印很简单:

underscore -i data.json print

一样:

cat data.json | underscore print

同样的事情,更明确:

cat data.json | underscore print --outfmt pretty

这个工具是我目前的激情项目,所以如果您有任何功能请求,我很有可能会解决它们。


321



我还更新了〜/ .bash_profile以获得以下行:alias underscor ='underscore print --outfmt pretty'现在我可以做卷曲 example.com/result.json | undercor并仍然使用下划线进行其他格式化 - Gal Bracha
谢谢戴夫!工具很好! alias pretty-json =“underrsore pretty”和curl输出令人赏心悦目 - Maxim Ponomarev
伟大的格式化工具,只需一个注释:将输出转发到文件(使用 -o 选项或 > )仅适用于 下划线打印。 下划线很漂亮 保存一个插入了颜色格式标志的文件,如: [32m, [33m, [39m 以及每个之前的一些不可打印,这使得JSON无效。然而, 下划线打印 单独不会向文件添加任何内容并完美地执行其格式化工作。 - tiurin
我爱 jq 但这对我没有双引号键的“JSON”非常有用。 - Bluu
@DaveDopson感谢伟大的工具!!要尝试一起使用它 jsonselect.org/#tryit ... - mycargus


我通常只做:

echo '{"test":1,"test2":2}' | python -mjson.tool

并检索选择数据(在这种情况下,“测试”的值):

echo '{"test":1,"test2":2}' | python -c 'import sys,json;data=json.loads(sys.stdin.read()); print data["test"]'

如果JSON数据在文件中:

python -mjson.tool filename.json

如果你想一次性完成这一切 curl 在命令行上使用身份验证令牌:

curl -X GET -H "Authorization: Token wef4fwef54te4t5teerdfgghrtgdg53" http://testsite/api/ | python -mjson.tool

168



python> = 2.6必需 - dim
如果json应该直接来自http api,这也是python中实现的一个很好的工具: github.com/jkbr/httpie - Florian
如果您安装了节点(并且不介意YAML样式输出),那么还有这个包: rafeca.com/prettyjson 所以你可以结束卷曲 | prettyjson - Iolo
如上所述,其中一个问题 python -mjson.tool 作为一个JSON漂亮的打印机,它并不总是发出JSON。例如。 1e1000变为Infinity(无论是使用python 2.x还是3.x)。 'jq。'总是生成JSON,但它不能保证精确保留非常大(或非常小的值)。 - peak


感谢J.F. Sebastian的非常有用的指示,这里有一个稍微增强的脚本,我想出了:

#!/usr/bin/python

"""
Convert JSON data to human-readable form.

Usage:
  prettyJSON.py inputFile [outputFile]
"""

import sys
import simplejson as json


def main(args):
    try:
        if args[1] == '-':
            inputFile = sys.stdin
        else:
            inputFile = open(args[1])
        input = json.load(inputFile)
        inputFile.close()
    except IndexError:
        usage()
        return False
    if len(args) < 3:
        print json.dumps(input, sort_keys = False, indent = 4)
    else:
        outputFile = open(args[2], "w")
        json.dump(input, outputFile, sort_keys = False, indent = 4)
        outputFile.close()
    return True


def usage():
    print __doc__


if __name__ == "__main__":
    sys.exit(not main(sys.argv))

82



将值加载到字典中时,订单将丢失:正常 dict 对象没有已定义的顺序。尝试 json.dumps(json.loads('{"b": 1, "a": 2}'), sort_keys=False) 然而你会发现它们已经被交换了。要修复它,请导入 OrderedDict 和 load 通过 object_pairs_hook=OrderedDict。 - icktoofay
您可以使用以下命令将脚本更改为从标准输入读取: inputFile = sys.stdin。这可以让你把东西管道传递到脚本,如下所示: curl http://somewhere.com/foo.json | pp_json.py - Gabe Johnson
为了避免使用@ icktoofay的评论进行排序,请像这样导入OrderedDict: from collections import OrderedDict。 - Hugo
谢谢@icktoofay。这允许我创建以下vim函数: com! FormatJSON %!python -c "from collections import OrderedDict; import sys; import json; j = json.load(sys.stdin, object_pairs_hook=OrderedDict); json.dump(j, sys.stdout, sort_keys=False, indent=4, separators=(',', ': '))"  请注意,分隔符必须设置为(',',':')以避免添加尾随空格: bugs.python.org/issue16333 - blindsnowmobile
伟大的片段!我用过 sort_keys = True 相反,因为我想用它来比较json文件,它就像一个魅力。 - JL Peyret


在* nix上,从stdin读取并写入stdout更好:

#!/usr/bin/env python
"""
Convert JSON data to human-readable form.

(Reads from stdin and writes to stdout)
"""

import sys
try:
    import simplejson as json
except:
    import json

print json.dumps(json.loads(sys.stdin.read()), indent=4)
sys.exit(0)

把它放在一个文件中(之后我命名为“prettyJSON”) ANC回答你的路径和路径 chmod +x 它,你很高兴。


66



实际上,使用stdin / stdout更加灵活和简单。谢谢你指出来。 - AnC
对于期望命名文件的程序,使用/ dev / stdin,ditto for out和err。 - dvogel
FYI fileinput.input() 如果在命令行中没有给出文件,则从stdin读取。 例 - jfs
fileinput.input()无法处理最后一次检查时没有换行的文件。 - Zachary Vance
stdin.read()无法停止......我怎么能阻止这个? - xiaoweiz


使用Perl,使用CPAN模块 JSON::XS。它安装了一个命令行工具 json_xs

验证:

json_xs -t null < myfile.json

整理JSON文件 src.jsonpretty.json

< src.json json_xs > pretty.json

如果你没有 json_xs,试试 json_pp 。 “pp”用于“纯perl” - 该工具仅在Perl中实现,没有绑定到外部C库(这是XS代表的,Perl的“扩展系统”)。


65



似乎是Cygwin的标准配置! - Janus Troelsen
json_pp可以以相同的方式使用,并且很可能很容易安装在您的系统上(在Debian上它位于'perl'包中)。 - MichielB
仅供参考,在我的Mac OS X 10.9系统上,json_pp可自动使用。 - Gregg Williams
或者,pp是“漂亮的印刷品”.. - FliiFe
-t null 给我 null:不是有效的toformat......但是让它脱颖而出。谢谢。 - Lucas


如果你使用npm和Node.js,你可以这样做 npm install -g json 然后通过管道传递命令 json。做 json -h 获得所有选项。它还可以拉出特定字段并使输出着色 -i

curl -s http://search.twitter.com/search.json?q=node.js | json

64



这是迄今为止我最喜欢的答案。 - Jon Deaton