【问题标题】:Problem with bash readarray -t array assignment when jq outputs an empty stringjq输出空字符串时bash readarray -t数组赋值的问题
【发布时间】:2021-01-13 11:39:39
【问题描述】:

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

#!/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[@]}"

还有输出

string
1

1

0

因此,使用readarray -t 将空字符串读入 bash 数组显示数组长度为 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')"

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

[
    {
        "Header": {
            "Region": "dc1",
            "Tenant": "tenant1",
            "Stage": "test"
        },
        "Body": {
            "monitors": []
        }
    }
]

这里是带有填充内容的 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"
                }
            ]
        }
    }
]

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

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

有哪些替代方法可以处理上述情况?

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

谢谢

【问题讨论】:

  • an empty string 这不是一个空字符串,它有一个换行符。
  • 你试过用read -a代替mapfile/readarray吗?

标签: arrays bash indexing jq content-length


【解决方案1】:

为什么会这样?

因为它读取一行。来自bash manual here document

[n]

[...] 结果以单个字符串的形式提供,附加换行符,在其标准输入(或文件描述符 n,如果指定了 n)上的命令。

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

readarray -t b < <(printf "%s" "$emptystring")

注意事项:

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

【讨论】:

  • 感谢您的评论。我认为 jq 的退出状态不适用于我的情况,因为我只想看到 jq 调用的结果是什么,并根据该结果做出决定。如果我需要先检查退出状态,然后根据退出状态进行另一个 jq 调用 - 这是重复工作。
  • 似乎这个构造 readarray -t URL_names &lt; &lt;( jq -r '. [].Body.monitors[].name' &lt;&lt;&lt;"$URL_list_json" | sort) 应该可以完成这项工作。
  • If I need to check exit status first and then based on the exit status to do another jq call - that's a duplication of efforts ?只是if ! output=$(jq something); then echo no data; fi
猜你喜欢
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2011-08-17
  • 2023-03-15
  • 2021-08-01
  • 1970-01-01
  • 2021-03-15
  • 2020-07-31
相关资源
最近更新 更多