在bash中,逻辑表达式应该在哪里否定?

3

如果您想组合多个测试,如何在bash中否定一个测试?

代码如下:

if ! [ $(pgrep Xvfb) ] || [ ! -v DISPLAY ]; then
    echo starting xvfb
    mkdir -p /tmp/xvfb
    Xvfb :1 -fbdir /tmp/xvfb > /tmp/xvfb_output 2>&1 &
    export DISPLAY=:1
fi

这段代码应该是被源码调用,如果Xvfb没有运行,则需要启动它。 之前缺少了|| [ ! -v DISPLAY ]这部分来检查该变量的存在。

要对一个测试进行否定,可以使用! [ ... ][ ! ... ],两者似乎都可以工作。

推理正确吗,应该使用[ ! ...],因为它在测试内部,因此更清晰(并且效率稍高)?

1个回答

5

我非常确定在效率方面,否定词的放置不重要。至于易读性,您可以像这样编写if语句:

if ! (test "$(pgrep Xvfb)" -a -n "${DISPLAY:+1}"); then

这样你就只有一个否定词和一个测试。

我同意你的观点,

if ! [ $(pgrep Xvfb) ] || [ ! -v DISPLAY ]; then

是含糊不清的,而

if [ ! $(pgrep Xvfb) ] || [ ! -v DISPLAY ]; then

则不是。


1
@user 是的,我通常更喜欢使用 test expr 表达式而不是 [ expr ]。在这种情况下,我觉得方括号比较繁重,特别是因为根据我的经验,结束括号在 shell 脚本中检测条件结束时并没有什么用处。当然,这只是我的个人意见。如果您喜欢这种表示法,请使用方括号。 - Julien Lopez
1
[ $(pgrep Xvfb) ]本身就是一个错误。你希望pgrep的输出是一个有效的非空字符串,以便[ ... ]测试通过。但这并不可靠,也不是一个好主意。幸运的是(因为它很明智),pgrep有有意义的返回代码。因此,为了测试它是否找到了某些东西,你需要if pgrep Xvfb &>/dev/null; then echo "do something now that we found Xvfb"; fi。对于这种情况,即if ! pgrep Xfvb &>/dev/null || [ ! -v DISPLAY ]; then ....; fi。我还要注意,如果DISPLAY被取消设置,则会多次运行Xvfb,这可能或可能不是你想要的。 - Etan Reisner
1
@EtanReisner 同意,这就是为什么我在我的建议中使用了 "$(pgrep Xvfb)",但我忘记在我的答案中加上备注。我还修改了第二个测试,因为 test-v 选项不适用于所有的 shells。 - Julien Lopez
1
您的建议还使用了已经过时的“-a”选项,并且使用了不必要的子shell。 - Etan Reisner
1
不是因为事物不支持它,而是因为历史上的规范不够严谨,用户输入更容易实现,所以 POSIX 认为它已经过时了(请参见 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128_16)。 - Etan Reisner
显示剩余2条评论

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