如何在Shell脚本中解析JSON?

3

我运行了curl命令$(curl -i -o - --silent -X GET --cert "${CERT}" --key "${KEY}" "$some_url"),并将响应保存在变量response中。${response}如下所示:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 34
Connection: keep-alive
Keep-Alive: timeout=5
X-XSS-Protection: 1; 

{"status":"running","details":"0"}

我想解析JSON {"status":"running","details":"0"} 并将'running'和'details'分配给两个不同的变量,以便我可以同时打印状态和细节。而且如果状态等于错误,脚本应该退出。我正在尝试以下方法来完成任务 -

status1=$(echo "${response}" | awk '/^{.*}$/' | jq -r '.status')
details1=$(echo "${response}" | awk '/^{.*}$/' | jq -r '.details')
echo "Status: ${status1}"
echo "Details: ${details1}"
if [[ $status1 == 'error' ]]; then
    exit 1
fi

我希望只解析一次JSON,而不是两次。因此,我想将以下行合并,但仍将状态和详细信息分配给两个单独的变量 -

status1=$(echo "${response}" | awk '/^{.*}$/' | jq -r '.status')
details1=$(echo "${response}" | awk '/^{.*}$/' | jq -r '.details')

你的 curl 命令是什么样子的?如果你无论如何都要丢弃头信息,那么你可以在第一次请求时就将它们从 $response 中省略掉。 - Benjamin W.
在上方添加了curl命令。 - JavaDeveloper
2
如果你去掉 -i,就不会获得头文件了。 - Benjamin W.
3个回答

5

首先,停止使用-i参数来执行curl命令。这样就不需要使用awk(或任何其他方式对头部进行修剪)。

其次:

{
  IFS= read -r -d '' status1
  IFS= read -r -d '' details1
} < <(jq -r '.status + "\u0000" + .details + "\u0000"' <<<"$response")

使用NUL作为分隔符的优点在于,它是唯一一个不能出现在C风格字符串值中的字符(这是shell变量值存储的方式)。

1
您可以使用类似以下的结构:

您可以使用这样的构造:

read status1 details1 < <(jq -r '.status + " " + .details' <<< "${response}")

你可以使用read将不同的输入分配给两个变量(或者一个数组,如果需要),并使用jq打印你需要的数据,用空格隔开。

2
如果您想允许任意字符串而不是依赖于空格,您可以使用空字节,如 https://dev59.com/8anka4cB1Zd3GeqPU9s4 所述。 - Benjamin W.

1

正如Benjamin所建议的那样,仅检索json是更好的方法。Poshi的解决方案很可靠。

然而,如果你正在寻找最紧凑的方法来做到这一点,如果你只是要从中提取其他变量,并且只需要在一次性基础上执行此操作,则无需将响应保存为变量。只需直接将curl传递到管道中:

curl "whatever" | jq -r '[.status, .details] |@tsv' 

or

curl "whatever" | jq -r '[.status, .details] |join("\t")'

并且你将获得为你提供的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接