使用 Unix 工具解析 JSON

Parsing JSON with Unix tools

提问人:auser 提问时间:12/24/2009 最后编辑:wejoeyauser 更新时间:4/17/2023 访问量:1679373

问:

我正在尝试解析从 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=text

JSON bash 解析 jq

评论

6赞 martinr 12/24/2009
呃,这不是一个好的 json 解析顺便说一句......字符串中的转义字符呢?等等 SO 上是否有 python 答案(甚至是 perl 答案......
1赞 steveha 12/29/2009
Python 对此的答案是简单地使用一个 Python JSON 库来实际解析 JSON。sed 和 AWK 提供了正则表达式,但这些都不是正确解析 JSON 问题的好解决方案。
74赞 BryanH 2/5/2013
每当有人说“问题 X 可以用其他语言 Y 轻松解决”时,这就是“我的工具箱只有一块石头来钉钉子......何必为别的事烦恼呢?
27赞 jfs 5/30/2013
@BryanH:除了有时语言 Y 可以更有能力解决特定问题 X,而不管建议 Y 的人知道多少种语言。
21赞 Diosney 11/18/2014
有点晚了,但就这样吧。.这很容易解决任务,并且只用grep,并且非常适合简单的JSON。对于复杂的 JSON,您应该使用适当的解析器。grep -Po '"'"version"'"\s*:\s*"\K([^"]*)' package.json

答:

1701赞 Brian Campbell 12/24/2009 #1

有许多工具是专门为从命令行操作 JSON 而设计的,并且比使用 Awk 操作要容易得多,也更可靠,例如 jq

curl -s 'https://api.github.com/users/lambda' | jq -r '.name'

您还可以使用可能已经安装在系统上的工具(例如使用 json 模块的 Python)来执行此操作,从而避免任何额外的依赖关系,同时仍然具有适当的 JSON 解析器的好处。下面假设您要使用 UTF-8,原始 JSON 应该用 UTF-8 进行编码,并且大多数现代终端也使用这种编码:

蟒蛇 3:

curl -s 'https://api.github.com/users/lambda' | \
    python3 -c "import sys, json; print(json.load(sys.stdin)['name'])"

蟒蛇 2:

export PYTHONIOENCODING=utf8
curl -s 'https://api.github.com/users/lambda' | \
    python2 -c "import sys, json; print json.load(sys.stdin)['name']"

常见问题解答

为什么不是纯壳解决方案?

标准的 POSIX/Single Unix 规范 shell 是一种非常有限的语言,它不包含用于表示序列(列表或数组)或关联数组(在其他语言中也称为哈希表、映射、字典或对象)的工具。这使得在可移植的 shell 脚本中表示解析 JSON 的结果有些棘手。有一些黑客方法可以做到这一点,但如果键或值包含某些特殊字符,其中许多方法可能会中断。

Bash 4 及更高版本、zsh 和 ksh 支持数组和关联数组,但这些 shell 并非普遍可用(macOS 在 Bash 3 中停止更新 Bash,因为从 GPLv2 更改为 GPLv3,而许多 Linux 系统没有开箱即用地安装 zsh)。你可以编写一个可以在 Bash 4 或 zsh 中工作的脚本,其中之一在当今大多数 macOS、Linux 和 BSD 系统上都可用,但要编写一个适用于这种多语言脚本的 shebang 行是很困难的。

最后,在 shell 中编写一个完整的 JSON 解析器将是一个足够重要的依赖项,您不妨使用现有的依赖项,例如 jq 或 Python。它不会是一行,甚至不是一小段五行的片段,就可以很好地实现。

为什么不使用 awk、sed 或 grep?

可以使用这些工具从具有已知形状并以已知方式格式化的 JSON 中进行一些快速提取,例如每行一个键。在其他答案中有几个建议的例子。

但是,这些工具是为基于行或基于记录的格式而设计的;它们不是为递归分析具有可能的转义字符的匹配分隔符而设计的。

因此,这些使用 awk/sed/grep 的快速而肮脏的解决方案可能很脆弱,如果输入格式的某些方面发生变化,例如折叠空格,或向 JSON 对象添加额外的嵌套级别,或字符串中的转义引号,它们就会中断。一个足够健壮的解决方案,可以在不中断的情况下处理所有JSON输入,也将是相当庞大和复杂的,因此与添加另一个对Python的依赖关系没有太大区别。jq

我以前不得不处理由于 shell 脚本中的输入解析不佳而被删除的大量客户数据,因此我从不推荐以这种方式可能很脆弱的快速而肮脏的方法。如果您正在进行一些一次性处理,请参阅其他答案以获取建议,但我仍然强烈建议您只使用现有的经过测试的 JSON 解析器。

历史笔记

这个答案最初推荐的是 jsawk,它应该仍然可以工作,但使用起来比 更麻烦一些,并且依赖于安装一个独立的 JavaScript 解释器,它比 Python 解释器更不常见,所以上面的答案可能更可取:jq

curl -s 'https://api.github.com/users/lambda' | jsawk -a 'return this.name'

这个答案最初也使用了问题中的 Twitter API,但该 API 不再起作用,因此很难复制示例进行测试,并且新的 Twitter API 需要 API 密钥,所以我改用 GitHub API,无需 API 密钥即可轻松使用。原始问题的第一个答案是:

curl 'http://twitter.com/users/username.json' | jq -r '.text'

评论

8赞 Szymon Sadło 6/17/2016
@thrau +1。jq:它在存储库中可用,并且非常易于使用,因此它比 jsawk 好得多。我测试了几分钟,jq 赢得了这场战斗
2赞 Martijn Pieters 9/9/2016
请注意,在 Python 2 中,如果要将输出通过管道传递给另一个命令,则该语句将始终编码为 ASCII,因为您在管道中使用 Python。插入命令以设置不同的输出编码,适合您的终端。在 Python 3 中,在本例中默认为 UTF-8(使用函数)。printPYTHONIOENCODING=<desired codec>print()
7赞 Andy Fraley 4/20/2018
使用 brew install jq 在 OSX 上安装 jq
5赞 Serge Stroobandt 10/27/2018
curl -s等价于 ,而 means 即没有字符串引号。curl --silentjq -rjq --raw-output
0赞 NotTooTechy 5/15/2020
python -c “导入请求;r=requests.get('api.github.com/users/lambda');print r.json()['name'];“ .最简单的!
121赞 martinr 12/24/2009 #2

使用 Python 的 JSON 支持,而不是使用 AWK!

像这样的东西:

curl -s http://twitter.com/users/username.json | \
    python -c "import json,sys;obj=json.load(sys.stdin);print(obj['name']);"

macOS v12.3 (Monterey) 删除了 /usr/bin/python,因此我们必须用于 macOS v12.3 及更高版本。/usr/bin/python3

curl -s http://twitter.com/users/username.json | \
    python3 -c "import json,sys;obj=json.load(sys.stdin);print(obj['name']);"

评论

8赞 martinr 12/24/2009
请原谅我试图想出一个好的回应......:我会更加努力的。党派之争需要的不仅仅是写一个笨拙的剧本来摆脱它!
11赞 m3nda 2/15/2016
为什么在该单行解决方案中使用 obj 变量?没用,反正根本不存?你用的例子写得更少,比如:.json.load(sys.stdin)['"key']"curl -sL httpbin.org/ip | python -c "import json,sys; print json.load(sys.stdin)['origin']"
0赞 Heath Borders 4/13/2022
/usr/bin/python在macOS上不存在,所以现在需要使用python3。12.3
80赞 Dennis Williamson 12/24/2009 #3

你问过如何搬起石头砸自己的脚,我在这里提供弹药:

curl -s 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^text/ {print $2}'

您可以使用代替 .但是完全排除它们似乎也具有预期的效果。tr -d '{}'sed

如果要去掉外部引号,请通过管道将上述结果通过sed 's/\(^"\|"$\)//g'

我认为其他人已经敲响了足够的警钟。我会拿着手机待命叫救护车。准备就绪时开火。

评论

13赞 Dennis Williamson 12/24/2009
这种疯狂的方式,阅读这个:stackoverflow.com/questions/1732348/......
3赞 eth0 1/27/2015
我已经阅读了所有答案,这个答案非常适合我,没有任何额外的依赖关系。+1
1赞 AlexHalkin 8/12/2015
这就是我一直在寻找的。唯一的更正 - 提供用于删除引号的 sed 命令对我不起作用,我改用了 sed 's/“//g'
5赞 ghostdog74 12/24/2009 #4

以下是使用 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
        }
    }
}'
14赞 boecko 4/27/2011 #5

使用 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]);"

评论

3赞 lucapette 5/4/2011
这是我最喜欢的;)顺便说一句,你可以用 ruby -rjson 做短它来需要库
0赞 Zack Morris 8/16/2018
请注意,在 Ruby 中不需要 final(它仅用于将通常位于不同行上的语句连接成一行)。;
0赞 Peter Mortensen 5/2/2022
链接已断开 (404)。
154赞 jnrg 6/12/2011 #6

跟随 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

评论

44赞 juan 3/28/2013
正如 OP 所问的那样,您将如何提取特定密钥?
2赞 Andrea Richiardi 5/12/2013
到目前为止最好的答案恕我直言,无需在大多数发行版上安装任何其他内容,您可以.谢谢!| grep field
9赞 Cheeso 6/4/2014
如果我没记错的话,这一切都是格式化 JSON。它不允许调用方从输出中选择特定字段,就像 xpath 解决方案或基于“JSON 指针”的内容一样。
8赞 christopher 12/28/2017
我最终只得到了一个键值对,但不是值本身。
3赞 CpILL 9/3/2018
jq通常不会在 Python 安装时安装。另外,一旦你进入 Python,你不妨一路走来,用import json...
331赞 Brendan OConnor 7/28/2011 #7

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

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

这个正则表达式比你想象的要强大;例如,它可以很好地处理嵌入逗号和转义引号的字符串。我认为,只要再做一点工作,你就可以做一个实际上可以保证提取值的,如果它是原子的。(如果它有嵌套,那么正则表达式当然不能这样做。

为了进一步清理(尽管保持字符串的原始转义),您可以使用类似的东西: .(我这样做是为了这个分析| perl -pe 's/"text"://; s/^"//; s/",$//'

对于所有坚持使用真正的JSON解析器的仇恨者 - 是的,这对于正确性至关重要,但是

  1. 要进行非常快速的分析,例如计算值以检查数据清理错误或大致了解数据,在命令行上敲出一些东西会更快。打开编辑器编写脚本会分散注意力。
  2. grep -o比 Python 标准库快几个数量级,至少在对推文(每个推文为 ~2 KB)执行此操作时是这样。我不确定这是否只是因为速度慢(我应该在某个时候与 yajl 进行比较);但原则上,正则表达式应该更快,因为它是有限状态并且更可优化,而不是必须支持递归的解析器,在这种情况下,花费大量 CPU 为你不关心的结构构建树。(如果有人编写了一个有限状态换能器来执行适当的(深度限制)JSON 解析,那就太棒了!同时,我们有“grep -o”。jsonjson

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

最后一个更古怪的解决方案:我编写了一个脚本,它使用 Python 并将您想要的键提取到制表符分隔的列中;然后,我通过管道传递一个包装器,该包装器允许对列进行命名访问。在这里:json2tsv 和 tsvawk 脚本。因此,对于此示例,它将是:jsonawk

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

这种方法不能解决 #2,比单个 Python 脚本效率低下,而且有点脆弱:它强制对字符串值中的换行符和制表符进行规范化,以配合 awk 的字段/记录分隔的世界视图。但它确实让你停留在命令行上,比 .grep -o

评论

14赞 Robert 12/4/2013
您忘记了整数值。grep -Po '"text":(\d*?,|.*?[^\\]",)'
3赞 Brendan OConnor 12/5/2013
Robert:是的,我的正则表达式是针对该字段的字符串值编写的。整数可以按照你说的添加。如果你想要所有类型,你必须做越来越多的事情:booleans、null。数组和对象需要更多的工作;在标准正则表达式下,只能进行深度限制。
11赞 jfs 8/25/2014
1. jq .name 在命令行上运行,不需要“打开编辑器来编写脚本”。2. 你的正则表达式产生错误结果的速度有多快并不重要
10赞 JeffCharter 9/7/2015
如果你只想要这些值,你可以向它抛出 awk。| grep -Po '"text":.*?[^\\]",'|awk -F':' '{print $2}'
56赞 Jens 6/8/2016
似乎在OSX上缺少该选项。我在 OSX 10.11.5 上进行了测试,并且是 .我让它在 OSX 上使用“扩展正则表达式”选项。上面的命令是 .-Pgrep --versiongrep (BSD grep) 2.5.1-FreeBSDgrep -Eo '"text":.*?[^\\]",' tweets.json
195赞 paulkmoore 12/6/2011 #8

基于这里的一些建议(尤其是在评论中)建议使用 Python,我很失望没有找到一个例子。

因此,这里有一个单行代码,用于从一些 JSON 数据中获取单个值。它假定您正在(从某处)通过管道传输数据,因此在脚本上下文中应该很有用。

echo '{"hostname":"test","domainname":"example.com"}' | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hostname"]'

评论

0赞 Joe Heyming 4/12/2014
我在下面增强了这个答案以使用 bash 函数:curl 'some_api' |getJsonVal '密钥'
3赞 akavel 3/23/2015
谢谢!为了更快速和肮脏的JSON解析,我已将其包装到bash函数中:这样我就可以编写:&更多类似的可怕东西...顺便说一句,似乎没有必要,看起来在默认情况下工作正常(?jsonq() { python -c "import sys,json; obj=json.load(sys.stdin); print($1)"; }curl ...... | jsonq 'json.dumps([key["token"] for key in obj], indent=2)'obj[0]obj
4赞 CyberEd 8/17/2016
obj[0]解析时导致错误。删除后工作正常。{ "port":5555 }[0]
1赞 ka3ak 7/27/2021
我得到“文件”<string>“,第 1 行导入 json,sys;obj=json.load(sys.stdin);print obj[“hostname”] ^ SyntaxError: invalid syntax ' when running the example
3赞 chill appreciator 11/3/2021
@ka3ak尝试而不是最后print(obj["hostname"])print obj["hostname"]
6赞 jaypal singh 12/7/2011 #9

你可以尝试这样的事情——

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

更新 (2020)

我对外部工具(例如 Python)的最大问题是您必须处理包管理器和依赖项才能安装它们。

但是,现在我们有一个独立的静态工具,可以通过 GitHub Releases 和 Webi (webinstall.dev/jq) 轻松跨平台安装,我建议:jq

Mac、Linux:

curl -sS https://webi.sh/jq | bash

视窗 10:

curl.exe -A MS https://webi.ms/jq | powershell

备忘单https://webinstall.dev/jq

原创 (2011)

TickTick 是一个用 bash 编写的 JSON 解析器(少于 250 行代码)。

以下是作者在他的文章《想象一个 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

评论

0赞 Thomas Fournet 9/26/2019
有没有办法再次将这个 people 变量打印成 json 字符串?这将是非常有用的
1赞 Hvitis 1/31/2021
感谢您的安装链接,这让我明白了。这非常简单。从数组中解压缩 obj:
1赞 spuder 11/5/2021
链接已断开。现在,它会将您带到一个恶意站点,该站点试图在您的浏览器中运行硬币矿工
0赞 Peter Mortensen 5/2/2022
@spuder:什么链接?有几个。
1赞 coolaj86 5/3/2022
我刚刚检查了链接。对我来说,一切看起来都很好。我的猜测是机器人添加了垃圾链接,然后一个模组回来并稍后修复了它。
5赞 kev 4/11/2012 #11

你可以使用 jshon

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

评论

0赞 Roger 1/27/2017
该网站说:“两倍的速度,1/6的内存”......然后:“Jshon 解析、读取和创建 JSON。它被设计为尽可能在 shell 内部可用,并取代了由 grep/sed/awk 组成的脆弱的 adhoc 解析器以及由 perl/python 制作的重量级单行解析器。"
0赞 qodeninja 7/8/2017
这被列为在 Bash 中解析 JSON 的推荐解决方案
0赞 gMale 5/21/2020
摆脱结果周围的引号的最简单方法是什么?
2赞 tonybaldwin 12/10/2012 #12

我已经完成了此操作,“解析”特定值的 JSON 响应,如下所示:

curl $url | grep $var | awk '{print $2}' | sed s/\"//g

显然,这里的$url将是 Twitter URL,$var将是“文本”来获取该变量的响应。

真的,我认为我正在做的 OP 唯一遗漏的就是 grep 与他寻求的特定变量的行。AWK 抓取行中的第二项,然后用 sed 去掉引号。

比我聪明的人可能会用 AWK 或 grep 完成整个思考。

现在,你可以用 just sed 完成这一切:

curl $url | sed '/text/!d' | sed s/\"text\"://g | sed s/\"//g | sed s/\ //g

因此,没有 AWK,没有 grep......我不知道为什么我以前没有想到这一点。嗯......

评论

0赞 tonybaldwin 12/10/2012
实际上,使用 sed,您可以做到
2赞 tripleee 12/4/2014
和管道是浪费的反模式。你的最后一个例子可以很容易地重写,但就像其他人指出的那样,这是容易出错和脆弱的方法,首先不应该推荐。grep | awk | sedsed | sed | sedcurl "$url" | sed '/text/!d;s/\"text\"://g;s/\"//g;s/\ //g'
0赞 Ferroao 8/21/2019
我不得不使用 grep -oPz 'name\“:\”.*?\“' curloutput |sed 's/name\“:/\n/g'
26赞 nickl- 1/24/2013 #13

使用 PHP CLI 解析 JSON

这可以说是题外话,但由于优先权占主导地位,如果不提及我们值得信赖和忠实的 PHP,这个问题仍然是不完整的,我说得对吗?

它使用相同的示例 JSON,但让我们将其分配给一个变量以减少模糊性。

export JSON='{"hostname":"test","domainname":"example.com"}'

现在,为了PHP的优点,它使用了file_get_contentsphp://stdin 流包装器。

echo $JSON | php -r 'echo json_decode(file_get_contents("php://stdin"))->hostname;'

或者正如使用 fgets 和 CLI 常量 STDIN 上已经打开的流所指出的那样。

echo $JSON | php -r 'echo json_decode(fgets(STDIN))->hostname;'

评论

0赞 IcanDivideBy0 9/23/2013
您甚至可以用代替$argnfgets(STDIN)
0赞 IcanDivideBy0 9/23/2013
哎呀,使用 -E 或 -R 标志,并且仅当 JSON 内容在一行上时......$argn
151赞 jfs 5/30/2013 #14

你可以下载适用于你的平台的 jq 二进制文件并运行 ():chmod +x jq

$ curl 'https://twitter.com/users/username.json' | ./jq -r '.name'

它从 json 对象中提取属性。"name"

jq 主页说它就像 JSON 数据一样。sed

评论

2赞 jbyler 4/22/2014
同意。我无法从公认的答案中与 jsawk 进行比较,因为我没有使用它,但对于本地实验(安装工具是可以接受的),我强烈推荐 jq。下面是一个稍微宽泛的示例,它采用数组的每个元素,并使用选定的数据合成一个新的 JSON 对象:curl -s https://api.example.com/jobs | jq '.jobs[] | {id, o: .owner.username, dateCreated, s: .status.state}'
3赞 Ben Jacobs 10/22/2014
喜欢这个。重量非常轻,而且由于它是普通的旧 C,因此几乎可以在任何地方编译。
1赞 lauhub 12/19/2014
最实用的:它不需要第三方库(而 jsawk 需要)并且易于安装(OSX:brew install jq)
3赞 Brandon K 5/27/2015
对于我的用例来说,这是最实用、最容易实现的答案。对于 Ubuntu (14.04) 系统,一个简单的 apt-get install jq 将该工具添加到我的系统中。我正在将 AWS CLI 响应的 JSON 输出输送到 jq 中,将值提取到响应中嵌套的某些键非常有效。
1赞 thrau 2/29/2016
这比 jsawk 快得多,这是我最近遇到的问题,因为对 spidermonkey 的调用成本很高。
7赞 BeniBela 5/31/2013 #15

也有XML文件的人,可能想看看我的Xidel。它是一个命令行界面,无依赖的 JSONiq 处理器。(也就是说,它还支持用于XML或JSON处理的XQuery。

问题中的例子是:

 xidel -e 'json("http://twitter.com/users/username.json")("name")'

或者使用我自己的非标准扩展语法:

 xidel -e 'json("http://twitter.com/users/username.json").name'

评论

1赞 Reino 1/13/2019
或者现在更简单:(或,或)。xidel -s https://api.github.com/users/lambda -e 'name'-e '$json/name'-e '($json).name'
145赞 Jay 8/27/2013 #16

使用 Node.js

如果系统安装了 Node.js,则可以将打印和评估脚本标志与 JSON.parse 一起使用,以提取所需的任何值。-p-e

一个简单的例子,使用JSON字符串并拉出“foo”的值:{ "foo": "bar" }

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

评论

1赞 Rnd_d 11/26/2013
谢谢!但就我而言,它仅适用于 -e 标志node -p -e 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
41赞 nicerobot 5/8/2014
管道!curl -s https://api.github.com/users/trevorsenior | node -pe "JSON.parse(require('fs').readFileSync('/dev/stdin').toString()).name"
4赞 Eliran Malka 3/1/2017
这是我最喜欢的解决方案;使用一种语言 (javascript) 来解析它自然的数据结构 (JSON)。似乎是最正确的。另外 - Node 可能已经在系统上可用,您不必使用 JQ 的二进制文件(这看起来像是另一个正确的选择)。
0赞 Youness 7/5/2017
这是 bash 脚本函数: # jsonv 获取特定属性的 json 对象值 # 第一个参数是 json 文档 # 第二个参数是应该返回值的属性 get_json_attribute_value() { node -pe 'JSON.parse(process.argv[1])[process.argv[2]]' “$1” “$2” }
11赞 Ilya Boyandin 10/15/2018
以下内容适用于 Node.js 10:cat package.json | node -pe 'JSON.parse(fs.readFileSync(0)).version'
4赞 mcnabicus 2/3/2014 #17

在 shell 脚本中解析 JSON 是很痛苦的。使用更合适的语言创建一个工具,以符合 shell 脚本约定的方式提取 JSON 属性。您可以使用新工具解决即时的 shell 脚本问题,然后将其添加到工具包中以备将来使用。

例如,考虑一个工具 jsonlookup,如果我说它将返回在标准输入的属性访问中定义的属性令牌中定义的属性 id,这可能是 JSON 数据。如果该属性不存在,则该工具不返回任何内容(退出状态 1)。如果解析失败,则退出状态 2 并显示一条消息到标准错误。如果查找成功,该工具将打印属性的值。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
50赞 Joe Heyming 2/6/2014 #18

将 Bash 与 Python 结合使用

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

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

然后

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 确保至少有 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"
}

评论

0赞 Cheeso 6/4/2014
没有 bash 函数的单行代码:curl http://foo | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["environment"][0]["name"]'
1赞 Per Johansson 6/27/2014
sys.stdout.write()如果您希望它同时适用于 Python 2 和 3。
0赞 Joe Heyming 7/8/2014
我认为它应该更改为system.stdout.write(obj$1)。这样你就可以说:getJsonVal “['environment']['name']”,就像@Cheeso的例子一样
1赞 Joe Heyming 9/23/2016
@Narek 在这种情况下,它看起来像这样: 函数getJsonVal() { py -x "json.dumps(json.loads(x)$1, sort_keys=True, indent=4)"; }
1赞 Peter Mortensen 5/2/2022
回复“.bash_rc文件”:不是“.bashrc文件”(不带下划线)吗?
3赞 shlomosh 4/1/2014 #19

对于更复杂的 JSON 解析,我建议使用 Python jsonpath 模块(由 Stefan Goessner 编写)-

  1. 安装它 -

    sudo easy_install -U jsonpath
    
  2. 使用它 -

    示例 file.json(来自 http://goessner.net/articles/JsonPath) -

    { "store": {
        "book": [
          { "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          { "category": "fiction",
            "author": "Evelyn Waugh",
            "title": "Sword of Honour",
            "price": 12.99
          },
          { "category": "fiction",
            "author": "Herman Melville",
            "title": "Moby Dick",
            "isbn": "0-553-21311-3",
            "price": 8.99
          },
          { "category": "fiction",
            "author": "J. R. R. Tolkien",
            "title": "The Lord of the Rings",
            "isbn": "0-395-19395-8",
            "price": 22.99
          }
        ],
        "bicycle": {
          "color": "red",
          "price": 19.95
        }
      }
    }
    

    解析它(提取所有价格为 10 <的书名)-

    cat file.json | python -c "import sys, json, jsonpath; print '\n'.join(jsonpath.jsonpath(json.load(sys.stdin), 'store.book[?(@.price < 10)].title'))"
    

    将输出 -

    Sayings of the Century
    Moby Dick
    

    注意:上述命令行不包括错误检查。对于具有错误检查功能的完整解决方案,您应该创建一个小型 Python 脚本,并使用 try-except 包装代码。

评论

0赞 Sridhar Sarnobat 8/20/2016
我在安装时遇到了一些麻烦,所以如果上述方法不起作用,您可以尝试以下类似的东西:1) 2) (我使用了 python 二进制文件的完整路径,因为我在安装多个 python 时遇到了一些问题)。jsonpathjsonpath_rw/usr/bin/python -m pip install jsonpath-rwcat ~/trash/file.json | /usr/bin/python -c "from jsonpath_rw import jsonpath, parse; import sys,json; jsonpath_expr = parse('store.book[0]'); out = [match.value for match in jsonpath_expr.find(json.load(sys.stdin))]; print out;"
3赞 RussellStewart 9/15/2014 #20

这是pythonpy的一个很好的用例:

curl 'http://twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'

评论

0赞 m3nda 2/15/2016
更短,python -c 模块在这里:)好。
35赞 maikel 10/30/2014 #21

这是使用大多数发行版上可用的标准 Unix 工具。它也适用于反斜杠 (\) 和引号 (“)。

警告:这与 jq 的功能不相上下,并且仅适用于非常简单的 JSON 对象。这是在无法安装其他工具的情况下回答原始问题的尝试。

function parse_json()
{
    echo $1 | \
    sed -e 's/[{}]/''/g' | \
    sed -e 's/", "/'\",\"'/g' | \
    sed -e 's/" ,"/'\",\"'/g' | \
    sed -e 's/" , "/'\",\"'/g' | \
    sed -e 's/","/'\"---SEPERATOR---\"'/g' | \
    awk -F=':' -v RS='---SEPERATOR---' "\$1~/\"$2\"/ {print}" | \
    sed -e "s/\"$2\"://" | \
    tr -d "\n\t" | \
    sed -e 's/\\"/"/g' | \
    sed -e 's/\\\\/\\/g' | \
    sed -e 's/^[ \t]*//g' | \
    sed -e 's/^"//'  -e 's/"$//'
}


parse_json '{"username":"john, doe","email":"[email protected]"}' username
parse_json '{"username":"john doe","email":"[email protected]"}' email

--- outputs ---

john, doe
[email protected]

评论

2赞 rtc11 4/6/2016
这太棒了。但是,如果 JSON 字符串包含多个电子邮件密钥,则解析器将输出 [email protected]“”[email protected]
0赞 alexmngn 3/15/2019
如果电子邮件中有破折号,则不起作用 [email protected]
2赞 Gwyneth Llewelyn 1/12/2021
从技术上讲,它们不是脚本语言的一部分,而是外部工具。sedawkbash
0赞 maikel 1/15/2021
@rtc11 你是对的。不幸的是,它不是一个成熟的JSON解析器。我在答案中添加了警告。谢谢!😄
1赞 maikel 1/15/2021
@GwynethLlewelyn 你是绝对正确的。我更正了描述。谢谢!😄
4赞 Adam Kurkiewicz 12/5/2014 #22

使用 Python 的两行代码。如果您正在编写单个 .sh 文件并且不想依赖另一个 .py 文件,则效果特别好。它还利用了管道的使用。 可以替换为将 JSON 文件打印到标准输出的任何内容。|echo "{\"field\": \"value\"}"

echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'

评论

0赞 Andrew Barber 12/5/2014
问题不是在寻找 Python 解决方案。也可以查看评论。
4赞 Max Barrass 5/25/2015 #23

这是一个很好的参考。在这种情况下:

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]} }  }'

评论

1赞 Viktova 3/19/2018
这个答案应该得到最高的票数,大多数(如果不是所有其他)答案都依赖于包(PHP、Python 等)。
1赞 tripleee 6/18/2018
不,恰恰相反,任何无用地使用 sed 的东西都不应该再获得任何赞成票。
0赞 Max Barrass 6/21/2018
SecKarma,没错!主题说UNIX工具对吗?tripleee,有没有 ON TOPIC 示例代码供我们查看吗?
4赞 cn007b 11/18/2015 #24

如果您安装了 PHP 解释器:

php -r 'var_export(json_decode(`curl http://twitter.com/users/username.json`, 1));'

例如:

我们有一个资源,它提供了带有国家/地区 ISO 代码的 JSON 内容:http://country.io/iso3.json,我们可以在带有 curl 的 shell 中轻松看到它:

curl http://country.io/iso3.json

但它看起来不是很方便,而且不可读。更好地解析 JSON 内容并查看可读结构:

php -r 'var_export(json_decode(`curl http://country.io/iso3.json`, 1));'

此代码将打印如下内容:

array (
  'BD' => 'BGD',
  'BE' => 'BEL',
  'BF' => 'BFA',
  'BG' => 'BGR',
  'BA' => 'BIH',
  'BB' => 'BRB',
  'WF' => 'WLF',
  'BL' => 'BLM',
  ...

如果你有嵌套数组,这个输出看起来会好得多......

2赞 Ehsan Chavoshi 6/22/2016 #25

我用它来从 ffprobe JSON 输出中提取视频持续时间:

MOVIE_INFO=`ffprobe "path/to/movie.mp4"  -show_streams -show_format -print_format json -v quiet`
MOVIE_SECONDS=`echo "$MOVIE_INFO"|grep -w \"duration\" |tail -1 | cut -d\" -f4 |cut -d \. -f 1`

它可用于从任何 JSON 文件中提取值:

value=`echo "$jsondata" | grep -w \"key_name\" |tail -1 | cut -d\" -f4

评论

1赞 tripleee 6/18/2018
如果这应该是有效的 shell 脚本,则最后一个片段中等号周围的空格是语法错误。
0赞 Ehsan Chavoshi 6/19/2018
@tripleee已更正。TNX。
3赞 Alexey Dubkov 8/27/2016 #26

如果在系统上可用,则: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

评论

0赞 Pruthvi Chitrala 8/26/2017
如何找到json-array长度用法json-query包?
15赞 Daniel Sokolowski 11/21/2016 #27

不幸的是,使用的最高票数答案返回了在我的方案中不起作用的完整匹配,但如果你知道 JSON 格式将保持不变,则可以使用 lookbehindlookahead 来提取所需的值。grep

# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="FooBar":")(.*?)(?=",)'
he\"llo
# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="TotalPages":)(.*?)(?=,)'
33
#  echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="anotherValue":)(.*?)(?=})'
100

评论

4赞 tripleee 6/18/2018
永远不知道 JSON 字典中元素的顺序。根据定义,它们是无序的。这正是为什么滚动自己的 JSON 解析器是一种注定要失败的方法的根本原因之一。
9赞 user2233949 3/20/2017 #28

现在 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 方法可以在没有 curl 的情况下做到这一点,那就是:

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 就是其中的几个。这是跨平台版本的 GitHub 页面:PowerShell

评论

0赞 MartinThé 11/19/2018
我曾经不喜欢 PowerShell,但我必须承认将 JSON 作为对象的处理非常好。
13赞 Stephen Quan 4/26/2017 #29

这是另一个 Bash 和 Python 混合答案。我发布了这个答案,因为我想处理更复杂的 JSON 输出,但是,降低了我的 bash 应用程序的复杂性。我想在 Bash 中从 http://www.arcgis.com/sharing/rest/info?f=json 中打开以下 JSON 对象:

{
  "owningSystemUrl": "http://www.arcgis.com",
  "authInfo": {
    "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
    "isTokenBasedSecurity": true
  }
}

在下面的示例中,我创建了自己的 Python 实现并利用了 Python。您会注意到,一旦我们将 Python 对象导入到 Python 字典中,我们就可以使用 Python 语法来导航字典。要浏览上述内容,语法为:jqunquotejson

  • data
  • data[ "authInfo" ]
  • data[ "authInfo" ][ "tokenServicesUrl" ]

通过在 Bash 中使用 magic,我们省略并只在数据右侧提供 Python 文本,即data

  • jq
  • jq '[ "authInfo" ]'
  • jq '[ "authInfo" ][ "tokenServicesUrl" ]'

请注意,在没有参数的情况下,jq 充当 JSON 美化器。使用参数,我们可以使用 Python 语法从字典中提取我们想要的任何内容,包括导航字典和数组元素。

下面是 Bash Python 混合函数:

#!/bin/bash -xe

jq_py() {
  cat <<EOF
import json, sys
data = json.load( sys.stdin )
print( json.dumps( data$1, indent = 4 ) )
EOF
}

jq() {
  python -c "$( jq_py "$1" )"
}

unquote_py() {
  cat <<EOF
import json,sys
print( json.load( sys.stdin ) )
EOF
}

unquote() {
  python -c "$( unquote_py )"
}

下面是 Bash Python 函数的示例用法:

curl http://www.arcgis.com/sharing/rest/info?f=json | tee arcgis.json
# {"owningSystemUrl":"https://www.arcgis.com","authInfo":{"tokenServicesUrl":"https://www.arcgis.com/sharing/rest/generateToken","isTokenBasedSecurity":true}}

cat arcgis.json | jq
# {
#     "owningSystemUrl": "https://www.arcgis.com",
#     "authInfo": {
#         "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#         "isTokenBasedSecurity": true
#     }
# }

cat arcgis.json | jq '[ "authInfo" ]'
# {
#     "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#     "isTokenBasedSecurity": true
# }

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]'
# "https://www.arcgis.com/sharing/rest/generateToken"

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]' | unquote
# https://www.arcgis.com/sharing/rest/generateToken
18赞 Helder Pereira 9/20/2017 #30

如果有人只想从简单的 JSON 对象中提取值而不需要嵌套结构,则可以在不离开 Bash 的情况下使用正则表达式。

这是我使用基于 JSON 标准的 bash 正则表达式定义的函数:

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

评论

0赞 vsbehere 1/8/2020
Helder Pereira 我们可以用这个函数提取嵌套属性值吗?
11赞 Alexander Mills 11/11/2017 #31

有一种更简单的方法可以从 JSON 字符串中获取属性。以文件为例,试试这个:package.json

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

我们使用 ,因为这会将文件的内容作为字符串获取到 Node.js 中,而不会有恶意内容逃脱其引用并被解析为代码的风险。process.env

评论

0赞 Charles Duffy 7/13/2018
使用字符串连接将值替换为解析为代码的字符串允许运行任意 node.js 代码,这意味着与从 Internet 上获取的随机内容一起使用非常不安全。在 JavaScript 中解析 JSON 的安全/最佳实践方法不仅仅是评估它,这是有原因的。
0赞 Alexander Mills 4/20/2019
@CharlesDuffy不确定我是否遵循,但 JSON.parse 调用应该更安全,因为实际上可以运行外部代码,而 JSON.parse 不能。require()
0赞 Charles Duffy 4/20/2019
当 - 并且仅当您的字符串实际上以绕过解析器的方式注入到 JSON 运行时中时,情况才正确。我没有看到这里的代码可靠地做到这一点。从环境变量中提取它并将其传递给,是的,您无疑是安全的......但在这里,JSON 运行时正在接收带有(受信任)代码的(不受信任的)内容。JSON.parse()
0赞 Charles Duffy 4/20/2019
...同样,如果你的代码从文件中读取 JSON 作为字符串并将该字符串传递给 ,那么你也是安全的,但这也不会发生在这里。JSON.parse()
2赞 Charles Duffy 4/20/2019
...啊,哎呀,还不如立即进入“如何”。问题在于,您正在将要传递给 JSON.parse() 的 shell 变量替换到代码中。您假设放置文本反引号将使内容保持文本,但这是一个完全不安全的假设,因为文本反引号可以存在于文件内容(以及变量)中,因此可以终止引用并进入未引用的上下文,其中值作为代码执行。
4赞 Anton Medvedev 1/26/2018 #32

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

Example of JSON formatting in Bash terminal

例子

使用匿名函数:

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

您可以使用 spread 运算符更新现有 JSON:

echo '{"count": 0}' | fx "{...this, count: 1}"

输出:

{"count": 1}

只是普通的 JavaScript。无需学习新语法。


更高版本的 fx 有一个互动模式!-

评论

8赞 tripleee 10/29/2018
如果你正在推广你自己的创作,你需要明确这一点。请参阅如何不成为垃圾邮件发送者。
0赞 Herve 2/12/2018 #33

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
1赞 Anand Singh 8/13/2018 #34

你可以使用 bashJson

它是 Python 的 JSON 模块的包装器,可以处理复杂的 JSON 数据。

让我们考虑一下文件中的这个示例 JSON 数据test.json

{
    "name":"Test tool",
    "author":"hack4mer",
    "supported_os":{
        "osx":{
            "foo":"bar",
            "min_version" : 10.12,
            "tested_on" : [10.1,10.13]
        },
        "ubuntu":{
            "min_version":14.04,
            "tested_on" : 16.04
        }
    }
}

以下命令从此示例 JSON 文件中读取数据

./bashjson.sh test.json name

打印:测试工具

./bashjson.sh test.json supported_os osx foo

印刷品:条形

./bashjson.sh test.json supported_os osx tested_on

打印:[10.1,10.13]

9赞 Pila 10/18/2018 #35

我不能在这里使用任何答案。jq、shell 数组、declare、grep -P、lookbehind、lookahead、Python、Perl、Ruby 甚至 Bash 都不可用。

其余的答案根本无法很好地工作。JavaScript 听起来很熟悉,但罐子上写着雀巢咖啡 - 所以这是不行的,太:)即使可用,对于我的简单需求 - 它们也会矫枉过正且速度缓慢。

然而,对我来说,从调制解调器的 JSON 格式回复中获取许多变量非常重要。我在 Bourne shell () 中使用它的路由器上有一个非常精简的 BusyBox!单独使用 AWK 没有任何问题:只需设置分隔符并读取数据即可。对于单个变量,仅此而已!sh

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 ' 开始 { FS=“”“;RS=“,” }; { if ($2 == “登录”) { print “Login=”“$4”“” } if ($2 == “name”) { print “Name=”“$4”“” } if ($2 == “updated_at”) { print “Updated=”“$4”“” } }' ) 回声“$Login,$Name,$Updated”

里面的空白没有任何问题。在我的使用中,相同的命令解析一个长的单行输出。使用 eval 时,此解决方案仅适用于可信数据。

很容易使它适应拾取未引用的数据。对于大量变量,可以使用 else if 实现边际速度增益。缺少数组显然意味着:没有额外的摆弄就没有多个记录。但是,在阵列可用的情况下,调整此解决方案是一项简单的任务。

@maikel 的 sed 答案几乎有效(但我不能对此发表评论)。对于我格式良好的数据 - 它有效。这里使用的示例不是那么多(缺少引号会把它扔掉)。它很复杂,很难修改。另外,我不喜欢必须进行 11 次调用来提取 11 个变量。为什么?我计时了 100 个循环,提取了 9 个变量:sed 函数用了 48.99 秒,我的解决方案用了 0.91 秒!不公平?仅对 9 个变量进行单次提取:0.51 秒对 0.02 秒。

4赞 Mike 3/25/2019 #36

我需要 Bash 中一些简短的东西,并且可以在 Python 2.7 和 3 的 vanilla Linux LSB 和 Mac OS 之外没有依赖项的情况下运行并处理错误,例如,将报告 JSON 解析错误和缺少属性错误而不会喷出 Python 异常:

json-extract () {
  if [[ "$1" == "" || "$1" == "-h" || "$1" == "-?" || "$1" == "--help" ]] ; then
    echo 'Extract top level property value from json document'
    echo '  Usage: json-extract <property> [ <file-path> ]'
    echo '  Example 1: json-extract status /tmp/response.json'
    echo '  Example 2: echo $JSON_STRING | json-extract status'
    echo '  Status codes: 0 - success, 1 - json parse error, 2 - property missing'
  else
    python -c $'import sys, json;\ntry: obj = json.load(open(sys.argv[2])); \nexcept: sys.exit(1)\ntry: print(obj[sys.argv[1]])\nexcept: sys.exit(2)' "$1" "${2:-/dev/stdin}"
  fi
}

评论

0赞 Aure77 12/17/2022
谢谢!如何处理嵌套对象?
3赞 2 revs, 2 users 64%Peter Mortensen #37

以下是使用 POSIX shell(带)和 shell 的书的答案:JSON.sh,4.7 KB。 localegrep

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

评论

0赞 Peter Mortensen 5/8/2022
这基本上是一个仅链接的答案。
1赞 Liu Hao 7/10/2020 #38

以下是 Node.js 就绪环境的简单方法:

curl -L https://github.com/trentm/json/raw/master/lib/json.js > json
chmod +x json
echo '{"hello":{"hi":"there"}}' | ./json "hello.hi"
6赞 Inian 1/18/2021 #39

现有答案中没有涵盖的一个有趣的工具是使用用 Go 编写的 gron,它有一个标语,上面写着 Make JSON greppable!,这正是它的作用。

因此,基本上将 JSON 分解为离散的赋值,查看它的绝对“路径”。与其他工具相比,它的主要优点是允许在不知道要搜索的记录的嵌套程度的情况下搜索值,而不会破坏原始的 JSON 结构gronjq

例如,我想从以下链接搜索该字段,我只是这样做'twitter_username'

% gron 'https://api.github.com/users/lambda' | fgrep 'twitter_username'
json.twitter_username = "unlambda";
% gron 'https://api.github.com/users/lambda' | fgrep 'twitter_username' | gron -u
{
  "twitter_username": "unlambda"
}

就这么简单。请注意(ungron 的缩写)如何从搜索路径中重建 JSON。只需要将搜索过滤到所需的路径,而不是将搜索表达式计算为正则表达式,而是将其计算为固定字符串(本质上是gron -ufgrepgrep -F)

另一个示例,用于搜索字符串以查看记录在嵌套结构中的位置

% echo '{"foo":{"bar":{"zoo":{"moo":"fine"}}}}' | gron | fgrep "fine"
json.foo.bar.zoo.moo = "fine";

它还支持使用命令行标志流式处理 JSON,您可以在其中连续对匹配记录的输入流进行排序。也具有零运行时依赖项。您可以下载适用于 Linux、Mac、Windows 或 FreeBSD 的二进制文件并运行它。-sgron

更多使用示例和行程可以在官方 Github 页面 - 高级用法中找到

至于为什么你可以使用其他JSON解析工具,请参阅项目页面的作者注释。gron

为什么我不应该只使用 jq?

JQ 很棒,而且比 Gron 强大得多,但随之而来的是复杂性。GRON 旨在让您更轻松地使用您已经知道的工具,例如 grep 和 sed。

评论

1赞 oguz ismail 1/18/2021
呵呵,我从来没听说过格隆。凉!
0赞 Henry 7/13/2021 #40

在以下之后使用 PHP:yum install php-cli

php -r " foreach(json_decode(file_get_contents('http://a.com/a.json'), true) as \$key => \$value) echo \$key.'='.\$value.\"\n\" ; "

评论

0赞 Neil Gatenby 8/17/2021
对我有好处,因为我的微型 ARM 芯片上已经有 php
3赞 jasenmichael 2/17/2022 #41

如果安装了 Node.js,这对我有用:

node -pe "require('${HOME}/.config/dev-utils.json').doToken"
3赞 Heath Borders 4/13/2022 #42

使用 Ruby 解析(默认情况下,解释器在所有 macOS 版本上都可用):/usr/bin/ruby

echo "${JSON}" | /usr/bin/ruby -e 'require "json"; puts JSON.parse(http://STDIN.read)["key1"]["nested_key_2"];'
1赞 ᐅdevrimbaris 5/12/2022 #43

您有多种选择。 您可以使用 trdsql [1] 来解析和转换 JSON/CSV 输入。以你为榜样;

trdsql "select attr1,attr2 from sample.json"

您也可以像在 SQL 中一样使用 where 子句。以CSV,JSON等格式输出。非常方便的工具。

根据我的经验,trdsql在处理属性嵌套值时有点问题,所以我在适当的时候使用qp [2]找到了解决方案。

cat sample.json | qp 'select attr1, attr2.detail.name where attr3=10'

请注意,没有 FROM。

要查看结果,您可以使用超快速的命令行 json 查看器工具,jless 查看输出 [3]。

Clickhouse 的街区里有一个新孩子。你可以从[4]中看到它的能力。

  1. https://github.com/noborus/trdsql
  2. https://jless.io
  3. https://github.com/f5io/qp
  4. https://clickhouse.com/blog/extracting-converting-querying-local-files-with-sql-clickhouse-local
2赞 Joseph Astrahan 5/19/2022 #44

如果您正在寻找一种原生 Mac 解决方案来解析 JSON(无外部库等),那么这是为您准备的。

此信息基于此处的一篇文章:https://www.macblog.org/parse-json-command-line-mac/

简而言之,由于早在 Mac OS Yosemite 就有用于运行 os ascript 的 apple 脚本的工具,但是如果您传递 -l 'Javascript' 标志,您就可以运行 javascript!这就是所谓的使用 JXA(用于自动化的 JavaScript)。

下面是为我自己的项目读取 JSON 文件的示例。

DCMTK_JSON=$(curl -s https://formulae.brew.sh/api/bottle/dcmtk.json) # -s for silent mode
read -r -d '' JXA <<EOF
function run() {
  var json = JSON.parse(\`$DCMTK_JSON\`);
  return json.bottles.$2.url;
}
EOF
DOWNLOAD_URL=$( osascript -l 'JavaScript' <<< "${JXA}" )
echo "DOWNLOAD_URL=${DOWNLOAD_URL}"

这里发生的事情是,我们将函数的输出存储到变量 JXA 中。然后,我们可以简单地运行 javascript 来使用 JSON.parse() 解析 JSON 内容。然后,只需将包含脚本的 JXA 变量传递给 osascript 工具,以便它可以运行 javascript。在我的示例中,如果您对此进行测试,则 2 美元指的是 arm64_monterey。javascript 立即运行的原因是 特殊函数 ,JXA 会寻找该函数并在完成后返回其输出。run()

请注意,EOF(文件末尾)用于处理多行文本输入,并且结尾 EOF 前面不能有任何空格来工作。

您只需打开终端并键入以下命令即可测试这是否适合您

osascript -l 'JavaScript' -e 'var app = Application.currentApplication(); app.includeStandardAdditions = true; app.displayDialog("Hello from JavaScript!");

这应该会弹出一个窗口,从 javascript 打招呼

1赞 jpseng 11/6/2022 #45

YAML 处理器 yq

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

输入

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

使用示例1

yq e '.name' $FILE

Angel

使用示例2

yq有一个很好的内置功能,可以使 JSON 和 YAML grep 可用

yq --output-format props $FILE

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

-2赞 seunggabi 3/10/2023 #46
pip3 install jq

parse() {
  key=$1

  python3 -c "
import sys
import jq
import json

input = json.load(sys.stdin)
output = jq.compile('$key').input(input).all()

if(isinstance(output, list)):
    output = ' '.join(output)

print(output)
"
}

name=$(aws emr describe-cluster --cluster-id $id | parse ".Cluster.Name")

echo $name
1赞 MonaPy 12/8/2023 #47

对于具有任何 python 3 环境的 python 用户:

python -m json.tool

它将从 stdin 获取 json 输入并很好地打印出 json。

要进行测试,假设你有一个 json 文件:test.json。并将 grep 传递给 grep your_key:

cat test.json | python -m json.tool
cat test.json | python -m json.tool | grep 'your_key'

假设你有 curl 的输出:

curl -s 'https://api.github.com/users/lambda' | python -m json.tool