使用Unix工具解析JSON

aus*_*ser 794 bash parsing json

我正在尝试解析从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]}'
Run Code Online (Sandbox Code Playgroud)

以上将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
% ...
Run Code Online (Sandbox Code Playgroud)

如何打印特定字段(用-v k=text?表示)?

Bri*_*ell 978

有许多专门用于从命令行操作JSON的工具,比使用Awk更容易,更可靠,例如jq:

curl -s 'https://api.github.com/users/lambda' | jq -r '.name'
Run Code Online (Sandbox Code Playgroud)

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

Python 2:

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

Python 3:

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

历史笔记

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

curl -s 'https://api.github.com/users/lambda' | jsawk -a 'return this.name'
Run Code Online (Sandbox Code Playgroud)

这个答案最初也使用了问题中的Twitter API,但该API不再有效,因此难以复制示例以进行测试,而新的Twitter API需要API密钥,因此我转而使用GitHub API.无需API密钥即可轻松使用.原始问题的第一个答案是:

curl 'http://twitter.com/users/username.json' | jq -r '.text'
Run Code Online (Sandbox Code Playgroud)

  • 我不想在项目中添加依赖项,因此我想使用sed/awk/curl,但jsawk似乎是最"强大"的解决方案. (23认同)
  • @ari我不确定你使用的是什么*nix风格,但Python是LSB(Linux标准基础)规范的一部分,它应涵盖今天的大多数发行版. (8认同)
  • 因为它每次启动spidermonkey,当你需要调用它时jsawk真的很慢.`jq`是个不错的选择 (7认同)
  • @thrau +1.jq它在存储库中可用并且超级易用,因此它比jsawk好得多.我测试了两分钟,jq赢得了这场战斗 (7认同)
  • ==>为jsawk安装依赖项:nspr,spidermonkey (6认同)
  • 使用 **brew install jq** 在 OSX 上安装 jq (5认同)
  • `curl -s` 等价于 `curl --silent`,而 `jq -r` 表示 `jq --raw-output` 即没有字符串引号。 (3认同)
  • 看起来它取决于外部二进制文件(spidermonkey-bin) (2认同)
  • 虽然docker容器通常没有python (2认同)
  • 请注意,在 Python 2 中,如果您将输出通过管道传输到另一个命令,则“print”语句将“始终”编码为 ASCII,因为您在管道中使用 Python。在命令中插入“PYTHONIOENCODING=&lt;所需的编解码器&gt;”以设置适合您的终端的不同输出编码。在 Python 3 中,本例中默认为 UTF-8(使用 `print()` *函数*)。 (2认同)

Bre*_*nor 270

要快速提取特定键的值,我个人喜欢使用"grep -o",它只返回正则表达式的匹配.例如,要从推文中获取"文本"字段,请执行以下操作:

grep -Po '"text":.*?[^\\]",' tweets.json
Run Code Online (Sandbox Code Playgroud)

这个正则表达式比你想象的更强大; 例如,它可以很好地处理嵌入了逗号并在其中包含转义引号的字符串.我认为通过更多的工作,你可以制作一个实际上可以保证提取值,如果它是原子的.(如果它有嵌套,那么正则表达式当然不能这样做.)

为了进一步清洁(虽然保持弦的原始逃逸),你可以使用类似的东西:| perl -pe 's/"text"://; s/^"//; s/",$//'.(我为此分析做了这个.)

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

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

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

最后一个更糟糕的解决方案:我编写了一个脚本,它使用Python json并将所需的键提取到制表符分隔的列中; 然后我通过一个包装器管道awk,允许对列进行命名访问. 在这里:json2tsv和tsvawk脚本.所以对于这个例子,它将是:

json2tsv id text < tweets.json | tsvawk '{print "tweet " $id " is: " $text}'
Run Code Online (Sandbox Code Playgroud)

这种方法没有解决#2问题,效率低于单个Python脚本,而且有点脆弱:它强制对字符串值中的换行符和制表符进行规范化,以便与awk的字段/记录分隔的世界视图一起使用.但它确实让你留在命令行,更正确grep -o.

  • 似乎在OSX上缺少`-P`选项.我在OSX 10.11.5上测试过,`grep --version`是`grep(BSD grep)2.5.1-FreeBSD`.我在OSX上使用了"扩展正则表达式"选项.上面的命令是`grep -Eo'"text":.*?[^ \\]",'tweets.json`. (30认同)
  • 你忘记了整数值.`grep -Po'"text":(\d*?,|.*?[^ \\]",)'` (11认同)
  • 1. [`jq .name`](http://stackoverflow.com/a/16838234/4279)在命令行上工作,它不需要"打开编辑器来编写脚本".2.正则表达式产生*错误*结果的速度无关紧要 (9认同)
  • 如果你只想要这些值,你可以向它抛出awk.`| grep -Po'"text":.*?[^ \\]",'| awk -F':''{print $ 2}'` (6认同)
  • 罗伯特:是的,我的正则表达式只是为该字段的字符串值编写的.可以像你说的那样添加整数.如果你想要所有类型,你必须做更多:booleans,null.数组和对象需要更多的工作; 在标准正则表达式下,只有深度限制才有可能. (3认同)
  • @JeffCharter或`grep -oP'(?&lt;=“ text”:“)。*?[^ \\](?=”,)'`以获取字符串值。 (2认同)

pau*_*ore 165

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

所以,这里有一个单行程序来从一些JSON数据中获取单个值.它假设您正在(从某处)管道数据,因此在脚本环境中应该是有用的.

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

  • 解析`{"port":5555}时,`obj [0]`导致错误.删除`[0]`后工作正常. (4认同)
  • @ka3ak 最后尝试 `print(obj["hostname"])` 而不是 `print obj["hostname"]` (3认同)
  • 谢谢!为了更快速和脏的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`在默认情况下工作正常(?). (2认同)

小智 131

继MartinR和Boecko的领导之后:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool
Run Code Online (Sandbox Code Playgroud)

那会给你一个非常友好的输出.很方便:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool | grep my_key
Run Code Online (Sandbox Code Playgroud)

  • 如OP所要求的,您将如何提取特定密钥? (36认同)
  • 所有这些都是格式化JSON,如果我没有弄错的话.它不允许调用者从输出中选择特定字段,如xpath解决方案,或基于"JSON指针"的东西. (7认同)
  • 我只是得到一个键值对,而不是它本身的值。 (3认同)
  • `jq` 通常不安装,而 python 则安装。另外,一旦你使用了 Python,你不妨全程使用“import json...”来解析它。 (3认同)
  • 到目前为止最好的答案imho,不需要在大多数发行版上安装任何其他东西,你可以`| grep field`.谢谢! (2认同)

jfs*_*jfs 123

您可以为您的平台下载jq二进制文件并运行(chmod +x jq):

$ curl 'https://twitter.com/users/username.json' | ./jq -r '.name'
Run Code Online (Sandbox Code Playgroud)

"name"从json对象中提取属性.

jq主页说它就像sed是JSON数据.

  • 只是为了记录,`jq`是一个了不起的工具. (27认同)
  • 对于我的用例,这是最实用且易于实现的答案。对于 Ubuntu (14.04) 系统,一个简单的 apt-get install jq 将该工具添加到我的系统中。我正在将来自 AWS CLI 响应的 JSON 输出通过管道传输到 jq 中,它非常适合将值提取到嵌套在响应中的某些键。 (3认同)
  • 同意.我无法与接受的答案中的jsawk进行比较,因为我没有使用它,但是对于本地实验(安装工具是可以接受的)我强烈推荐jq.这是一个稍微更广泛的示例,它采用数组的每个元素并使用选定的数据合成一个新的JSON对象:`curl -s https://api.example.com/jobs | jq'.jobs [] | {id,o:.owner.username,dateCreated,s:.status.state}'` (2认同)
  • 喜欢这个。重量非常轻,并且由于它使用的是普通的旧C语言,因此可以在几乎任何位置进行编译。 (2认同)

mar*_*inr 97

使用Python的JSON支持而不是使用awk!

像这样的东西:

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

  • 为什么在oneliner解决方案中使用obj变量?它没用,根本不存储?你可以用`json.load(sys.stdin)['"key']"`作为例如:`curl -sL httpbin.org/ip | python -c"import json,sys; print json.load(sys.stdin)['origin']"`. (9认同)
  • 请原谅我想要得到一个好的回应......:我会更加努力.党派关系需要的不只是写一个awk脚本来摆脱它! (5认同)

Jay*_*com 94

使用Node.js

如果系统安装了,则可以使用-pprint和-eevaulate脚本标记JSON.parse来提取所需的任何值.

一个使用JSON字符串{ "foo": "bar" }并提取"foo"值的简单示例:

$ node -pe 'JSON.parse(process.argv[1]).foo' '{ "foo": "bar" }'
bar
Run Code Online (Sandbox Code Playgroud)

因为我们可以访问cat和其他实用程序,所以我们可以将它用于文件:

$ node -pe 'JSON.parse(process.argv[1]).foo' "$(cat foobar.json)"
bar
Run Code Online (Sandbox Code Playgroud)

或任何其他格式,例如包含JSON的URL:

$ node -pe 'JSON.parse(process.argv[1]).name' "$(curl -s https://api.github.com/users/trevorsenior)"
Trevor Senior
Run Code Online (Sandbox Code Playgroud)

  • 管!`curl -s https://api.github.com/users/trevorsenior | node -pe"JSON.parse(require('fs').readFileSync('/ dev/stdin').toString()).name"` (29认同)
  • 以下适用于Node.js 10:`cat package.json | node -pe'JSON.parse(fs.readFileSync(0)).version'` (5认同)
  • 这是我最喜欢的解决方案; 使用语言(javascript)来解析它自然的数据结构(JSON).似乎是最正确的*.另外 - 节点可能已经在系统上可用,你不必使用jq的二进制文件(看起来像另一个*正确*选项). (3认同)

Pau*_*ce. 57

你问过如何用脚射击自己,我在这里提供弹药:

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

你可以用tr -d '{}'而不是sed.但完全抛弃它们似乎也会产生预期的效果.

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

我认为其他人已经发出足够的警报.我会站着用手机打电话给救护车.准备好时开火.

  • 疯狂的方式就是这样,请阅读:http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 (9认同)
  • 我已经阅读了所有答案,这个答案非常适合我,没有任何额外的依赖。+1 (3认同)

Joe*_*ing 41

在Python中使用Bash

在.bash_rc文件中创建一个bash函数

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

然后

$ curl 'http://twitter.com/users/username.json' | getJsonVal "['text']"
My status
$ 
Run Code Online (Sandbox Code Playgroud)

这是相同的功能,但有错误检查.

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))";
}
Run Code Online (Sandbox Code Playgroud)

其中$#-ne 1确保至少有1个输入,-t 0确保从管道重定向.

这个实现的好处是你可以访问嵌套的json值并获得json作为回报!=)

例:

$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']['a'][1]"
2
Run Code Online (Sandbox Code Playgroud)

如果你想要真正的幻想,你可以打印数据:

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"
}
Run Code Online (Sandbox Code Playgroud)

  • +1,但你应该摆脱[无用的`cat`](http://partmaps.org/era/unix/award.html) (2认同)

Coo*_*J86 27

TickTick是一个用bash编写的JSON解析器(<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
Run Code Online (Sandbox Code Playgroud)

  • 作为这里唯一强大的纯 bash 答案,这值得更多赞成。 (2认同)

nic*_*kl- 21

使用PHP CLI解析JSON

可以说是偏离主题但是由于优先权统治这个问题仍然不完整而没有提到我们可靠和忠实的PHP,我是对的吗?

使用相同的示例JSON但允许将其分配给变量以减少隐匿性.

$ export JSON='{"hostname":"test","domainname":"example.com"}'
Run Code Online (Sandbox Code Playgroud)

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

$ echo $JSON|php -r 'echo json_decode(file_get_contents("php://stdin"))->hostname;'
Run Code Online (Sandbox Code Playgroud)

或者指出在CLI常量STDIN中使用fgets和已打开的流.

$ echo $JSON|php -r 'echo json_decode(fgets(STDIN))->hostname;'
Run Code Online (Sandbox Code Playgroud)

的nJoy!


mai*_*kel 19

Native Bash版本:也适用于反斜杠(\)和引号(")

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":"john@doe.com"}' username
parse_json '{"username":"john doe","email":"john@doe.com"}' email

--- outputs ---

john, doe
johh@doe.com
Run Code Online (Sandbox Code Playgroud)

  • 这太棒了。但如果 JSON 字符串包含多个电子邮件密钥,则解析器将输出 john@doe.com""john@doe.com (2认同)
  • 从技术上讲,“sed”和“awk”不是“bash”脚本语言的一部分——它们是外部工具。 (2认同)

boe*_*cko 12

使用Ruby的版本和http://flori.github.com/json/

$ < file.json ruby -e "require 'rubygems'; require 'json'; puts JSON.pretty_generate(JSON[STDIN.read]);"
Run Code Online (Sandbox Code Playgroud)

或者更简洁:

$ < file.json ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"
Run Code Online (Sandbox Code Playgroud)

  • 这是我最喜欢的;)BTW你可以用ruby -rjson来缩短它以要求库 (3认同)

Dan*_*ski 10

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

# 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
Run Code Online (Sandbox Code Playgroud)

  • 您*永远*实际上*不知道*JSON 字典中元素的顺序。根据定义,它们是无序的。这正是为什么使用自己的 JSON 解析器是一种注定失败的方法的根本原因之一。 (4认同)

Ste*_*uan 8

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

{
  "owningSystemUrl": "http://www.arcgis.com",
  "authInfo": {
    "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
    "isTokenBasedSecurity": true
  }
}
Run Code Online (Sandbox Code Playgroud)

在以下示例中,我创建了自己的实现jqunquote利用了python. 您会注意到,一旦我们将 python 对象从jsonpython 字典中导入,我们就可以使用 python 语法来导航字典。要导航上述内容,语法是:

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

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

  • 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 )"
}
Run Code Online (Sandbox Code Playgroud)

以下是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
Run Code Online (Sandbox Code Playgroud)


Hel*_*ira 8

如果有人只想从简单的JSON对象中提取值而不需要嵌套结构,则可以使用正则表达式而无需费劲。

这是我使用基于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
}
Run Code Online (Sandbox Code Playgroud)

注意事项:不支持将对象和数组作为值,但是支持标准中定义的所有其他值类型。此外,只要它具有完全相同的键名,无论在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
Run Code Online (Sandbox Code Playgroud)


use*_*949 7

现在Powershell是跨平台的,我想我会抛弃它,因为我发现它非常直观且非常简单.

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json 
Run Code Online (Sandbox Code Playgroud)

ConvertFrom-Json将JSON转换为Powershell自定义对象,因此您可以轻松地使用此处的属性.例如,如果您只想要'id'属性,那么您只需执行此操作:

curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json | select -ExpandProperty id
Run Code Online (Sandbox Code Playgroud)

如果你想从Bash中调用整个东西,那么你必须像这样调用它:

powershell 'curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json'
Run Code Online (Sandbox Code Playgroud)

当然,有一种纯粹的Powershell方法可以在没有卷曲的情况下完成它,这将是:

Invoke-WebRequest 'https://api.github.com/users/lambda' | select -ExpandProperty Content | ConvertFrom-Json
Run Code Online (Sandbox Code Playgroud)

最后,还有'ConvertTo-Json',它可以轻松地将自定义对象转换为JSON.这是一个例子:

(New-Object PsObject -Property @{ Name = "Tester"; SomeList = @('one','two','three')}) | ConvertTo-Json
Run Code Online (Sandbox Code Playgroud)

哪个会生成这样的好JSON:

{
"Name":  "Tester",
"SomeList":  [
                 "one",
                 "two",
                 "three"
             ]
Run Code Online (Sandbox Code Playgroud)

}

不可否认,在Unix上使用Windows shell有点亵渎神灵,但Powershell在某些方面非常擅长,解析JSON和XML是其中的几个.这是跨平台版本https://github.com/PowerShell/PowerShell的GitHub页面


Ale*_*lls 7

有一种更简单的方法来从json字符串获取属性。以package.json文件为例,请尝试以下操作:

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

我们之所以使用,process.env是因为这会将文件的内容作为字符串获取到node.js中,而没有恶意内容转义引用并被解析为代码的风险。

  • ...啊,哎呀,不如马上进入“如何”。问题是*您正在将打算传递给`JSON.parse()`的shell变量替换到代码中*。您*假设*放置文字反引号将保持内容文字,但这是一个完全不安全的假设,因为文字反引号可以存在于文件内容(以及变量)中,因此可以终止引用并输入未引用的上下文其中值作为代码执行。 (2认同)

jay*_*ngh 6

你可以试试这样的——

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


小智 6

我不能在这里使用任何答案。没有可用的jq,没有shell数组,没有声明,没有grep -P,没有后向和超前,没有Python,没有Perl,没有Ruby,甚至-甚至Bash ...其余答案根本无法正常工作。JavaScript听起来很熟悉,但是锡说Nescaffe-所以也不行:)即使可用,就我的简单需求而言-它们也会过时且缓慢。

但是,从我的调制解调器的json格式回复中获取许多变量对我来说非常重要。我在路由器上用非常精简的BusyBox进行了处理!单独使用awk没问题:只需设置分隔符并读取数据。对于单个变量,仅此而已!

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

还记得我没有数组吗?我必须在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"
Run Code Online (Sandbox Code Playgroud)

内部没有任何问题。在我的使用中,相同的命令解析长单行输出。使用eval时,此解决方案仅适用于受信任的数据。使它适应拾取未引用的数据很简单。对于大量变量,使用else if可以实现边际速度增益。缺少数组显然意味着:没有多余的摆弄就没有多个记录。但是在有阵列的情况下,采用这种解决方案是一项简单的任务。

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


Ini*_*ian 6

现有答案中尚未涵盖的一个有趣的工具是使用gronGo 编写的,它的口号是“ Make JSON grepable!” 这正是它的作用。

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

例如,我想'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"
}
Run Code Online (Sandbox Code Playgroud)

就如此容易。请注意(ungron 的缩写)如何gron -u从搜索路径重建 JSON。需要的fgrep只是将搜索过滤到所需的路径,而不是让搜索表达式被计算为正则表达式,而是作为固定字符串(本质上是grep -F

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

% echo '{"foo":{"bar":{"zoo":{"moo":"fine"}}}}' | gron | fgrep "fine"
json.foo.bar.zoo.moo = "fine";
Run Code Online (Sandbox Code Playgroud)

它还通过其-s命令行标志支持流式 JSON,您可以在其中连续收集输入流以获取匹配的记录。还gron具有零运行时依赖性。您可以下载适用于 Linux、Mac、Windows 或 FreeBSD 的二进制文件并运行它。

更多使用示例和行程可以参见Github官方页面-高级使用

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

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

jq 很棒,而且比 gron 强大得多,但这种强大也带来了复杂性。gron 旨在让您更轻松地使用您已知的工具,例如 grep 和 sed。


gho*_*g74 5

这是使用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
        }
    }
}'
Run Code Online (Sandbox Code Playgroud)


kev*_*kev 5

你可以使用jshon:

curl 'http://twitter.com/users/username.json' | jshon -e text
Run Code Online (Sandbox Code Playgroud)


Ben*_*ela 5

也有xml文件的人可能想看看我的Xidel.它是一个cli,无依赖JSONiq处理器.(即它还支持XQuery for xml或json处理)

问题中的例子是:

 xidel -e 'json("http://twitter.com/users/username.json")("name")'
Run Code Online (Sandbox Code Playgroud)

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

 xidel -e 'json("http://twitter.com/users/username.json").name'
Run Code Online (Sandbox Code Playgroud)


Ant*_*dev 5

还有一个非常简单但功能强大的JSON CLI处理工具fx —— https://github.com/antonmedv/fx

Bash 终端中的 JSON 格式示例

例子

使用匿名函数:

$ echo '{"key": "value"}' | fx "x => x.key"
value
Run Code Online (Sandbox Code Playgroud)

如果不传入匿名函数param => ...,代码会自动转化为匿名函数。您可以通过此关键字访问 JSON:

$ echo '[1,2,3]' | fx "this.map(x => x * 2)"
[2, 4, 6]
Run Code Online (Sandbox Code Playgroud)

或者也只使用点语法:

$ echo '{"items": {"one": 1}}' | fx .items.one
1
Run Code Online (Sandbox Code Playgroud)

您可以传递任意数量的匿名函数来减少 JSON:

$ echo '{"items": ["one", "two"]}' | fx "this.items" "this[1]"
two
Run Code Online (Sandbox Code Playgroud)

您可以使用扩展运算符更新现有的 JSON:

$ echo '{"count": 0}' | fx "{...this, count: 1}"
{"count": 1}
Run Code Online (Sandbox Code Playgroud)

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


更新 2018-11-06

fx现在有交互模式(

https://github.com/antonmedv/fx

  • 如果您要宣传自己的创作,则需要明确说明。请参阅[如何不成为垃圾邮件发送者。](/help/promotion) (7认同)