我需要一种方法来检查它是否为空,而不是在脚本末尾,如果有的话,请采取特定的措施。
我已经尝试将其视为普通VAR,并使用-z进行检查,但这似乎行不通。在Bash中是否可以检查数组是否为空?
#1 楼
假设您的数组是$errors
,只需检查元素数是否为零即可。if [ ${#errors[@]} -eq 0 ]; then
echo "No errors, hooray"
else
echo "Oops, something went wrong..."
fi
#2 楼
在这种情况下,我通常使用算术扩展:if (( ${#a[@]} )); then
echo not empty
fi
评论
干净整洁!我喜欢。我还注意到,如果数组的第一个元素始终为非空,则(($ {#a}))(第一个元素的长度)也将起作用。但是,这将在a =('')上失败,而答案中给出的(($ $ ## a [@]}))将成功。
– cxw
18年8月15日在12:36
可能曾经是这样,但是我无法复制它。如果echo $ BASH_VERSION && a =('')&&((($ {#a [@]})))&& echo不为空|| echo empty恰好输出“ empty”,随意告诉您的版本。
–x-yuri
20 Dec 17 '21:38
#3 楼
您也可以将数组视为简单变量。这样,只需使用if [ -z "$array" ]; then
echo "Array empty"
else
echo "Array non empty"
fi
或使用另一面
if [ -n "$array" ]; then
echo "Array non empty"
else
echo "Array empty"
fi
该解决方案的问题是如果这样声明数组:
array=('' foo)
。这些检查将报告该数组为空,而显然不是。 (感谢@musiphil!)使用
[ -z "$array[@]" ]
显然也不是解决方案。未指定大括号会尝试将$array
解释为字符串(在这种情况下,[@]
是简单的文字字符串),因此始终报告为false:“文字字符串[@]
是否为空?”显然不是。评论
[-z“ $ array”]或[-n“ $ array”]不起作用。尝试array =(''foo); [-z“ $ array”] &&回显为空,即使array很明显不是空的,它也会打印为空。
–音乐爱好者
15年8月17日在23:25
[[-n“ $ {array [*]}”]]]将整个数组插入为字符串,并检查其长度是否为非零。如果您认为array =(“”“”)为空,而不是拥有两个空元素,那么这可能会很有用。
– Peter Cordes
17年9月19日在15:21
@PeterCordes我认为不行。该表达式的结果为单个空格字符,[[--n“”]]为“ true”,真可惜。您的评论正是我想做的。
–迈克尔
19年6月18日在16:37
@迈克尔:胡扯,你是对的。它仅适用于1元素的空字符串数组,而不适用于2元素。我什至检查了较旧的bash,但那里还是错误的。就像您说的那样,set -x显示了它如何扩展。我想我在发布之前没有测试该评论。 >。<您可以通过设置IFS =''使它起作用(在此语句周围保存/还原),因为“ $ {array [*]}”扩展将元素与IFS的第一个字符分隔开。 (如果未设置,则为空格)。但是,“如果IFS为空,则无需中间分隔符即可连接参数。” (用于$ *位置参数的文档,但对于数组我假设相同)。
– Peter Cordes
19年6月18日在16:57
@Michael:添加了执行此操作的答案。
– Peter Cordes
19年6月18日在17:35
#4 楼
我用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
和
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
在后一种情况下,您需要以下结构:
${array[@]:+${array[@]}}
在空数组或未设置数组上失败。那是如果您像我通常那样做。这提供了更严格的错误检查。在文档中:
-e
如果管道(请参阅管道)(可能由单个简单命令(请参见简单命令),列表(请参见列表))或复合命令(请参见复合命令)返回非零状态。如果失败的命令紧随一段时间或直到关键字,if语句中的测试部分,&&或||中执行的任何命令的一部分之后,命令列表立即出现,则外壳程序不会退出。列出除了最后一个&&或||之后的命令,管道中除最后一个命令之外的任何命令,或者该命令的返回状态用!反转。如果除子外壳程序以外的复合命令由于在-e被忽略时命令失败而返回非零状态,则外壳程序不会退出。 ERR陷阱(如果已设置)在外壳程序退出之前执行。
此选项分别适用于外壳程序环境和每个子外壳程序环境(请参阅命令执行环境),并且可能导致子外壳程序在执行其中的所有命令之前退出。
如果在忽略-e的上下文中执行复合命令或shell函数,则即使-e设置,复合命令或函数体内执行的所有命令都不会受到-e设置的影响。设置并且命令返回失败状态。如果复合命令或shell函数在忽略-e的上下文中执行时设置了-e,则该设置在复合命令或包含函数调用的命令完成之前不会生效。
-u
执行参数扩展时,将特殊参数“ @”或“ *”以外的未设置变量和参数视为错误。错误消息将被写入标准错误,并且非交互式外壳将退出。
如果不需要,请忽略
set -eu
部件。也请注意,那么在这里使用
:+${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
评论
使用-u时,您实际上应该使用$ {array [@] +“ $ {array [@]}”} cf stackoverflow.com/a/34361807/1237617
–雅库布·博琴斯基(Jakub Bochenski)
17年9月13日在14:52
@JakubBochenski您正在谈论哪个版本的bash? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9
–x-yuri
17年9月13日在18:28
单括号示例中的问题肯定是@。您可以使用*数组扩展,例如[“ $ {array [*]}”“],不是吗?不过,[[也可以正常工作。对于具有多个空字符串的数组,这两种方式的行为都令人惊讶。 [$ {#array [*]}]和[[“ $ {array [@]}”]]]对于array =()和array =('')均为假,但对于array =('''')为true (两个或多个空字符串)。如果希望一个或多个空字符串全部为true,则可以使用[$ {#array [@]} -gt 0]。如果您希望它们全部为假,则可以//将它们淘汰。
–eisd
18-09-2在6:42
@eisd我可以使用[“ $ {array [*]}”]],但是如果遇到这种表达式,对我来说很难理解它的作用。由于内插结果是根据字符串进行运算的。与[[]]相对,后者可以知道所插值的内容。也就是说,它可以知道它已传递给数组。 [[$ {array [@]}]]对我来说是“检查数组是否为非空”,而[“ $ {array [*]}”]对我来说是“检查所有数组元素的内插结果是否为非空字符串”。
–x-yuri
'18 Sep 2'在15:30
...对于有两个空字符串的行为,这一点都不令我感到惊讶。令人惊讶的是一个空字符串的行为。但是可以说是合理的。关于[$ {#array [*]}],您可能是指[“ $ {array [*]}”]],因为前者对于任意数量的元素都是正确的。因为元素数总是非空字符串。对于带有两个元素的后者,括号内的表达式扩展为'',这是非空字符串。至于[[$ {array [@]}]],他们只是认为(正确地)两个元素的任何数组都是非空的。
–x-yuri
18/09/2在15:46
#5 楼
如果要检测包含空元素的数组,例如arr=("" "")
为空,则与arr=()
相同,可以将所有元素粘贴在一起并检查结果是否为零长度。 (如果数组可能很大,则构建数组内容的展平副本对于性能而言不是理想的选择。但是希望您不对诸如此类的程序使用bash ...)但是
"${arr[*]}"
可以扩展为由IFS
的第一个字符分隔的元素。因此,您需要保存/恢复IFS并执行IFS=''
才能完成此工作,否则请检查字符串长度==数组元素的数量-1。(n
元素数组具有n-1
分隔符)。要一一处理,最简单的方法是用1 arr=("" "")
## Assuming default non-empty IFS
## TODO: also check for ${#arr[@]} -eq 0
concat="${arr[*]} " # n-1 separators + 1 space + array elements
[[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
用
set -x
### a non-empty element
$ arr=("" "x")
+ arr=("" "x")
$ concat="${arr[*]} "; [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
+ concat=' x '
+ [[ 3 -ne 2 ]]
+ echo not empty array
not empty array
### 2 empty elements
$ arr=("" "")
+ arr=("" "")
$ concat="${arr[*]} "; [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
+ concat=' '
+ [[ 2 -ne 2 ]]
+ echo empty array
empty array
不幸的是,这对于
arr=()
失败:[[ 1 -ne 0 ]]
。因此,您需要先分别检查是否为空数组。或使用
IFS=''
。也许您想保存/还原IFS而不是使用子Shell,因为您无法轻易地从子Shell中获得结果。# inside a () subshell so we don't modify our own IFS
(IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
示例:
$ arr=("" "")
$ (IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
+ IFS=
+ [[ -n '' ]]
+ echo empty array
empty array
可与
arr=()
一起使用-它仍然只是空字符串。评论
我赞成,但是我已经开始使用[[“ $ {arr [*]}” = * [![:space:]] *]],因为我可以指望至少一个非WS字符。
–迈克尔
19年6月18日在18:30
@Michael:是的,如果您不需要拒绝arr =(“”),那是一个不错的选择。
– Peter Cordes
19年6月18日在20:59
#6 楼
我更喜欢使用双括号:if [[ !${array[@]} ]]
then
echo "Array is empty"
else
echo "Array is not empty"
fi
双括号:https://stackoverflow.com/questions/669452/is-preferable-over-in -bash
#7 楼
就我而言,第二个答案还不够,因为可能会有空格。我来了: if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
echo "No options"
else
echo "Options found"
fi
评论
回声与使用shell内置程序相比,wc似乎不必要地效率低下。
– Peter Cordes
17/09/17在4:16
不知道我是否了解@PeterCordes,是否可以修改第二个答案'[$ {#errors [@]} -eq 0];以某种方式解决空白问题?我也希望内置。
– Micha
17年9月18日在13:10
空格到底是怎么引起问题的? $#扩展为一个数字,即使在opts + =(“”)之后也可以正常工作。例如未选择opts + =(“”); opts + =(“”);回显“ $ {#opts [@]}”,我得到2。您能显示一个不起作用的示例吗?
– Peter Cordes
17年9月18日在13:33
很久以前了IIRC原始源始终至少打印“”。因此,对于opts =“”或opts =(“”),我需要0,而不是1,忽略空的换行符或空字符串。
– Micha
17年9月19日在14:20
好的,因此您需要将opts =(“”)与opts =()相同?那不是一个空数组,但是您可以使用opts =(“”);检查是否有空数组或第一个元素为空。 [[“ $ {#opts [@]}” -eq 0 || -z“ $ opts”]] && echo空。请注意,您当前的答案对opts =(“”“ -foo”)说“无选项”,这完全是虚假的,并且可以重现该行为。您可以[[-z“ $ {opts [*]}”]]]插入所有数组元素到一个平面字符串中,-z检查是否为非零长度。如果检查第一个元素已足够,则-z“ $ opts”有效。
– Peter Cordes
17年9月19日在15:18
评论
请注意,=是字符串运算符。在这种情况下,它可以正常工作,但是我会改用正确的算术运算符-eq(以防万一我想切换到-ge或-lt等)。
–音乐爱好者
13年8月8日在19:27
不适用于set -u:“未绑定变量”-如果数组为空。
–user97619
17-4-8在19:56
@Igor:在Bash 4.4中为我工作。设置-u; foo =(); [$ {#foo [@]} -eq 0] &&回显为空。如果我未设置foo,则它会输出foo:未绑定变量,但这是不同的:数组变量根本不存在,而不是存在且为空。
– Peter Cordes
17 Sep 17'4:22
在使用set -u时也在Bash 3.2(OSX)中进行了测试-只要您先声明了变量,它就可以很好地工作。
– zeroimpl
18年8月5日在16:48