【问题标题】:Why did my boolean test switch in bash?为什么我的布尔测试在 bash 中切换?
【发布时间】:2016-09-01 16:44:41
【问题描述】:

我有这个 bash 函数来检查我是否在互联网上。当我需要在 bash 脚本中进行快速 if internet-connected 测试时,它会有所帮助。

由于上个月它非常有用,我尝试复制它的设计以拥有一个简单的 ubuntu 测试器来测试操作系统是否是 Ubuntu。然后就发生了这样的事情……

test.sh

internet-connected(){
    wget -q --spider http://google.com
    if [ $? -eq 1 ]
    then
        echo 'internet is connected'
        return 1
    else
        echo 'internet is not connected'
        return 0
    fi
}

echo "testing internet-connected"

if internet-connected
then
    echo 'connected'
else
    echo 'not connected'
fi

check-for-ubuntu(){
    tester=$(lsb_release -i | grep -e "Ubuntu" -c)
    if [ $tester -eq 1 ]
    then
        echo 'ubuntu detected'
        return 1
    else
        echo 'ubuntu not detected'
        return 0
    fi
}

echo ""
echo "testing check-for-ubuntu"

if check-for-ubuntu
then
    echo 'this is ubuntu'
else
    echo 'this is not ubuntu'
fi

输出

testing internet-connected
internet is not connected
connected

testing check-for-ubuntu
ubuntu detected
this is not ubuntu
[Finished in 0.9s]

我的问题

为什么这两个函数的逻辑似乎倒退了?

你们回答得很好,谢谢。

【问题讨论】:

  • 好问题,对我来说看起来很简单。调试 shell 脚本的标准第一步是将 set -x 放在开头,这样您就可以看到所有命令的执行情况。
  • 等待 - 两者相同 - 在两者情况下,来自函数内部的消息与来自函数外部的消息相反。
  • 我不确定我是否同意@Barmar 关于问题的质量——有很多与手头的问题无关的代码,因此违反了“M”(“最小”)部分MCVE.
  • @CharlesDuffy 我的意思是这是一个有趣的问题。而且我认为有两个测试用例进行比较会使示例更好 - 一个示例会是 too M.
  • @Barmar, ...当然,但不需要涉及外部代码。您可以摆脱 wget 调用或 lsb_release | ... 并将它们替换为任何人都可以在任何 POSIX 机器上运行的常量 truefalse 调用。

标签: linux bash shell ubuntu boolean-logic


【解决方案1】:

Shell 脚本不是 C(或 C++/Java/etc./etc./etc.)。

  • 0 表示成功 (true)。
  • 任何其他都意味着错误 (false)。

你的返回值是向后的。

【讨论】:

  • 出于退出状态的目的,即使在 C 中也是如此——这就是 (0) EXIT_SUCCESS 和 (1) EXIT_FAILURE 常量的用途。见the relevant glibc docs
  • 没错,但那是因为 C 程序的退出代码是由 shell 脚本读取的。
  • 我不同意这是一个外壳驱动的约定——它是一个逻辑驱动的约定——如果你有任何其他方式,你不能有更多一个错误代码,因此您无法通过退出状态区分不同类型的错误。因此,使用单字节退出代码的 UNIX 约定通常不会有用。
  • 是的,Unix 退出代码是“状态”,而不是“布尔”,因此是 shell 脚本的自然形式。零并不意味着“成功”,而是“没有错误”。
  • @CharlesDuffy 为什么这种“逻辑”不适用于像 C 这样的编程语言?为什么它们有很多真值,但只有一个假值?因此需要一个单独的errno 变量。
【解决方案2】:

您的check-for-ubuntu 可以使用grep -q

check-for-ubuntu() {
    lsb_release -i | grep -q "Ubuntu"
}

grep -q 将根据 lsb_release 命令中的模式 Ubuntu 返回 1 或 0。

【讨论】:

  • 但这并不能回答问题。
  • 这并不能解释为什么他的原始功能不起作用。对我来说它看起来很简单。
  • 是的,这对我来说也很简单。这只是避免多个命令执行相同操作的改进。
猜你喜欢
  • 2013-04-01
  • 2011-01-26
  • 1970-01-01
  • 2017-09-27
  • 2018-05-16
  • 2021-09-14
  • 1970-01-01
  • 2022-12-20
  • 1970-01-01
相关资源
最近更新 更多