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


当前回答

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

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

其他回答

如果你正在寻找一个本地Mac解决方案来解析JSON(没有外部库等…),那么这是为你。

此信息来自https://www.macblog.org/parse-json-command-line-mac/

简而言之,自从Mac OS Yosemite有一个运行苹果脚本的工具叫做osascript,但是如果你传递-l 'Javascript'标志,你可以运行Javascript !这就是所谓的使用JXA (JavaScript for Automation)。

下面是为我自己的项目读取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中。然后我们可以使用JSON.parse()简单地运行javascript来解析JSON内容。然后简单地将包含脚本的JXA变量传递给osascript工具,以便它可以运行javascript。在我的例子中,如果测试的话,$2指的是arm64_monterey。javascript立即运行的原因是特殊的run()函数,JXA将查找该函数并在完成时返回其输出。

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

您可以通过简单地打开终端并键入下面的命令来测试这是否适合您

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

这应该会弹出一个从javascript说hello的窗口

我需要在Bash中一些简短的东西,可以在没有依赖的情况下运行,而不是香草Linux LSB和Mac OS的Python 2.7和3,并处理错误,例如,将报告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
}

既然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方法来做它没有卷曲,这将是:

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

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

下面是一行程序,从JSON数据中获取单个值。它假设您将数据输送进来(从某个地方),因此在脚本上下文中应该很有用。

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

有很多专门为从命令行操作JSON而设计的工具,它们会比用Awk更容易、更可靠,比如jq:

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

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

Python 3:

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

Python 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 Specification shell是一种非常有限的语言,它不包含表示序列(列表或数组)或关联数组(在其他一些语言中也称为哈希表、映射、字典或对象)的工具。这使得在可移植的shell脚本中表示解析JSON的结果有些棘手。有一些简单的方法可以做到这一点,但如果键或值包含某些特殊字符,其中许多方法都可能会失效。

Bash 4 and later, zsh, and ksh have support for arrays and associative arrays, but these shells are not universally available (macOS stopped updating Bash at Bash 3, due to a change from GPLv2 to GPLv3, while many Linux systems don't have zsh installed out of the box). It's possible that you could write a script that would work in either Bash 4 or zsh, one of which is available on most macOS, Linux, and BSD systems these days, but it would be tough to write a shebang line that worked for such a polyglot script.

最后,在shell中编写一个完整的JSON解析器将是一个非常重要的依赖项,您还可以使用现有的依赖项,如jq或Python。要实现良好的实现,它不会是一行代码,甚至不会是五行代码片段。

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

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

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

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

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

历史记录

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

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'