jq 输出空字符串时 bash readarray -t 数组赋值的问题

Inv*_*999 8 arrays indexing bash content-length jq

首先 - 一个非常简单的代码:

#!/bin/bash

a_string="string"
readarray -t a <<<"$a_string"
echo "${a[@]}"
echo "${#a[@]}"

# read empty string into array
emptystring=""
readarray -t b <<<"$emptystring"
echo "${b[@]}"
echo "${#b[@]}"

# and now - empty array
c=()
echo "${c[@]}"
echo "${#c[@]}"
Run Code Online (Sandbox Code Playgroud)

和输出

string
1

1

0
Run Code Online (Sandbox Code Playgroud)

因此,将空字符串读入 bash 数组时readarray -t会显示数组长度为 1。只有真正的空数组的长度才是 0。

我的问题 - 为什么会发生这种情况?

就我而言 - 这是我的脚本中的一个片段 - 执行 API 调用、获取 JSON 并应用 jq 过滤器:

URL_list_json=$(curl -s --request GET "$curl_request" --header "Authorization: Bearer ${token}")
readarray -t URL_names <<<"$(echo "$URL_list_json" | jq -r '.[].Body.monitors[].name')"
Run Code Online (Sandbox Code Playgroud)

下面是一个 JSON 示例,它从 jq 调用中生成一个空数组:

[
    {
        "Header": {
            "Region": "dc1",
            "Tenant": "tenant1",
            "Stage": "test"
        },
        "Body": {
            "monitors": []
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

这里是 JSON,其中填充的内容从 jq 调用返回一个非空数组:

[
    {
        "Header": {
            "Region": "dc2",
            "Tenant": "tenant2",
            "Stage": "qa"
        },
        "Body": {
            "monitors": [
                {
                    "enabled": true,
                    "entityId": "TEST-674BA97E74FC74AA",
                    "name": "production.example.com"
                },
                {
                    "enabled": false,
                    "entityId": "TEST-3E2D23438A973D1E",
                    "name": "test.example.com"
                }
            ]
        }
    }
]

Run Code Online (Sandbox Code Playgroud)

我需要检查URL_names数组是否为空。如果不为空,则迭代内容。如果为空 - 意味着 jq 没有返回任何结果 - 白色记录并继续。

如果我使用它if ((${#URL_names[@]}))作为检查数组是否为空的方法,即使数组只有来自 jq 调用的空字符串,它也会返回 1,因此此逻辑失败。

处理上述情况的替代方法是什么?

我可以将 jq 过滤器的输出分配给一个字符串,然后使用if语句检查该字符串是否为空,如果非空,则将该字符串分配给一个数组,但这会引入额外的元素。通过这种方法,我可以完全跳过使用数组 - 我希望仅使用数组来完成此任务。

谢谢

Kam*_*Cuk 6

为什么会发生这种情况?

因为它读一行。来自bash 手册这里的文档

[n]<<< 字

[...] 结果作为单个字符串提供给标准输入上的命令(如果指定了 n,则为文件描述符 n),并附加换行符。

因为有换行符,readarray所以读取一个空行。你可以这样做:

readarray -t b < <(printf "%s" "$emptystring")
Run Code Online (Sandbox Code Playgroud)

笔记:

  • echo "$var"不是优选的。printf "%s" "$var"在 posix shell 中执行,<<<"$var"在 bash 中执行(并且您不关心额外的换行符)。
  • <<<"$(...)"总是看起来很奇怪——<<<无论如何都必须分配一个子shell。做< <(...)
  • 你想做:readarray -t URL_names < <(<<<"$URL_list_json" jq -r '.[].Body.monitors[].name')
  • 如果您想检查数组是否为空,请在 中进行检查jq我看到前任。 jq --exit-status '.[].Body.monitors[].name'只需检查退出状态即可。