在 Bash 中检查数组是否为空

Mar*_*der 162 bash

我有一个数组,当我的脚本运行时,它会填充不同的错误消息。

我需要一种方法来检查脚本末尾是否为空,如果是,则采取特定操作。

我已经尝试将其视为普通 VAR 并使用 -z 进行检查,但这似乎不起作用。有没有办法在 Bash 中检查数组是否为空?

Mic*_*ton 211

假设您的数组是$errors,只需检查元素数是否为零。

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi
Run Code Online (Sandbox Code Playgroud)

  • 请注意 `=` 是一个字符串运算符。在这种情况下它碰巧工作正常,但我会使用适当的算术运算符 `-eq` 代替(以防万一我想切换到 `-ge` 或 `-lt` 等)。 (11认同)
  • 不适用于`set -u`:“未绑定变量” - 如果数组为空。 (10认同)

x-y*_*uri 39

在这种情况下,我通常使用算术展开:

if (( ${#a[@]} )); then
    echo not empty
fi
Run Code Online (Sandbox Code Playgroud)


wge*_*get 11

您也可以将数组视为一个简单的变量。这样,只需使用

if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi
Run Code Online (Sandbox Code Playgroud)

或使用另一边

if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi
Run Code Online (Sandbox Code Playgroud)

与解决方案的问题是,如果一个数组声明如下:array=('' foo)。这些检查会将数组报告为空,而显然不是。(感谢@musiphil!)

使用[ -z "$array[@]" ]显然也不是解决方案。不指定大括号试图解释$array为字符串([@]在这种情况下是一个简单的文字字符串),因此总是报告为 false:“文字字符串是否为[@]空?” 显然不是。

  • `[ -z "$array" ]` 或 `[ -n "$array" ]` 不起作用。试试 `array=('' foo); [ -z "$array" ] && echo empty`,即使 `array` 显然不是空的,它也会打印 `empty`。 (8认同)
  • 这个答案完全错误,为什么是8分?它认为在许多不同的情况下数组错误地为空 (3认同)
  • `[[ -n "${array[*]}" ]]` 将整个数组插入为一个字符串,您可以检查该字符串的非零长度。如果你认为 `array=("" "")` 是空的,而不是有两个空元素,这可能很有用。 (2认同)
  • 这只是检查第一个元素是否为空,而不是数组。 (2认同)

x-y*_*uri 6

我检查了它bash-4.4.0

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty
Run Code Online (Sandbox Code Playgroud)

bash-4.1.5

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,您需要以下构造:

${array[@]:+${array[@]}}
Run Code Online (Sandbox Code Playgroud)

因为它不会在空或未设置的数组上失败。那就是如果你set -eu像我通常那样做。这提供了更严格的错误检查。从文档

-e

如果管道(请参阅管道)(可能由单个简单命令(请参阅简单命令)、列表(请参阅列表)或复合命令(请参阅复合命令)组成)返回非零状态,则立即退出。如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、if 语句中测试的一部分、在 && 或 || 中执行的任何命令的一部分,则 shell 不会退出 列表除了最后一个 && 或 || 之后的命令,管道中除最后一个之外的任何命令,或者如果命令的返回状态正在用 ! 反转。如果子shell 以外的复合命令由于命令在-e 被忽略时失败而返回非零状态,则shell 不会退出。如果设置了 ERR 上的陷阱,则会在 shell 退出之前执行。

该选项分别适用于shell环境和每个子shell环境(参见命令执行环境),并且可能导致子shell在执行子shell中的所有命令之前退出。

如果复合命令或 shell 函数在 -e 被忽略的上下文中执行,则复合命令或函数体内执行的任何命令都不会受到 -e 设置的影响,即使设置了 -e 并且命令返回故障状态。如果复合命令或 shell 函数在忽略 -e 的上下文中执行时设置了 -e,则在复合命令或包含函数调用的命令完成之前,该设置不会产生任何影响。

-u

执行参数扩展时,将未设置的变量和特殊参数 '@' 或 '*' 以外的参数视为错误。错误消息将写入标准错误,并且非交互式 shell 将退出。

如果您不需要它,请随意省略:+${array[@]}部分。

还要注意,[[在这里使用运算符是必不可少的,[你会得到:

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty
Run Code Online (Sandbox Code Playgroud)