Bash条件语句:如何“与”多个表达式?(如果[!-z $VAR && -e $VAR])

286

我想我不太清楚如何进行“and”测试。我想确保一个参数使用[ -e $VAR ]良好工作,但结果发现即使是空字符串也会被评估为真;而这并非我所想要的。

那么我该如何将它们“and”在一起呢?或者有没有其他一元测试可以实现我想要的功能?

5个回答

538
if [ ! -z "$var" ] && [ -e "$var" ]; then
      # something ...
fi

10
这种解决方案即使在严格遵守 POSIX 标准的 shell 中也可以工作,因此也适用于 bash;不过,要充分利用 "bashisms",请参考 @paxdiablo 的回答。 - mklement0
2
非常高兴看到这个建议,而不是已过时的 -a - Charles Duffy
1
我找到了另一个优秀且详细的解释 - https://dev59.com/UHA65IYBdhLWcg3w1SfU - valentt

72

来自 bash 手册:

[[ expression ]] - 根据条件表达式的计算结果返回0或1的状态。

对于条件表达式,其中之一选项是:

expression1 && expression2 - 如果 expression1expression2 都为真,则返回真。

因此可以将它们 and 在一起,如下所示(-n-z 的相反,因此我们可以摆脱 !):

if [[ -n "$var" && -e "$var" ]] ; then
    echo "'$var' is non-empty and the file exists"
fi

然而,在这种情况下,我认为它并不是必需的,-e xyzzy 如果 xyzzy 文件 存在,并且可以很容易地处理空字符串,则为真。 如果这正是你想要的,那么你实际上不需要 -z 非空检查:

pax> VAR=xyzzy
pax> if [[ -e $VAR ]] ; then echo yes ; fi
pax> VAR=/tmp
pax> if [[ -e $VAR ]] ; then echo yes ; fi
yes
换句话说,只需使用:
if [[ -e "$var" ]] ; then
    echo "'$var' exists"
fi

1
我们可以使用[[ -e "$var" ]] && echo "'$var' exists"来缩短它。 - jaypal singh
1
是的,如果它只有一行(就像我的例子一样)。但如果条件块更加复杂,我不会这样做。 - paxdiablo
如果只有一个(甚至是很长的)命令,使用这种形式是有意义的,因为它更短。 - avp

9
if [ -n "$var" -a -e "$var" ]; then
    do something ...
fi

 


10
因为POSIX没有定义在具有复杂测试集的情况下与[一起使用的行为,所以我们应该避免在[中使用-a-o。我在这里阅读到了这个信息(http://mywiki.wooledge.org/BashGuide/TestsAndConditionals?highlight=%28conditional%29#Conditional_Blocks_.28if.2C_test_and_.5B.5B.29)。 - jaypal singh
2
@jaypal-singh 您是正确的,但是该主题具有“bash”标签,没有提到POSIX,因此我发布了这个版本,在bash和其他一些现代shell下可以工作。 - Slava Semushin
2
如果您假定使用bash或其他现代shell,则更没有理由推荐-a - chepner
即使使用bash,这些测试的行为在所有边角情况下都没有定义得很好。考虑 [ "$var1" -o "$var2" ];如果 var1=(var2=),那么我们所拥有的是一个测试 -o 是否为空,而不是 var1var2 中是否有任何一个非空。这种模棱两可是现代(即90年代后)带有正确引用的“test”命令中“x$var”习惯用法的唯一合理原因,而且这种习惯用法需要消失。 - Charles Duffy

4

只需引用您的变量:

[ -e "$VAR" ]

这个表达式如果$VAR为空,就会被翻译成[ -e "" ]
你的版本不起作用是因为它被翻译成了[ -e ]。在这种情况下,bash只是检查单个参数(-e)是否是非空字符串。
从manpage中可以看出:

使用一组基于参数数量的规则来评估条件表达式...

1个参数

当且仅当参数不为空时,表达式为真。

(此外,这个解决方案还有一个额外的好处,就是可以处理包含空格的文件名)

1

我现在找到了答案。感谢您的建议!

for e in ./*.cutoff.txt; do
if grep -q -E 'COX1|Cu-oxidase' $e
then
    echo xyz >$e.match.txt
else
    echo
fi

if grep -q -E 'AMO' $e
then
    echo abc >$e.match.txt
else
    echo
fi; done

对此有任何评论吗?看起来grep两次效率不高,但它能正常工作...


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