在 shell 脚本中表示布尔值的最佳实践是什么?

在 shell 脚本中表示布尔值的最佳实践是什么?

我知道, 中有布尔值bash,但我没有看到它们在任何地方使用过。

我想为我的机器上一些经常查找的信息编写一个包装器,例如,是否插入/安装了这个特定的 USB 驱动器。

实现这一目标的最佳实践是什么?

  • 一根绳子?

    drive_xyz_available=true
    
  • 一个数字(0 为真,≠0 为假)?

    drive_xyz_available=0    # evaluates to true
    
  • 一个函数?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }
    

我主要想知道,其他想要使用包装器的人会期望什么。他们会期望一个布尔值、一个类似变量的命令或一个要调用的函数吗?

从安全角度来看,我认为第二种选择是最安全的,但我很想听听您的经历。

答案1

bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

只需将变量设置为除非空之外的任何值即可使上述工作正常进行,尽管[ -n "$var" ]会更短(如果不是那么明显的话)。

一般来说,当脚本将环境变量解释为 true 或 false 时,它​​会将任何值解释为 true(有时使用所述值来配置某些选项)否则将 null 值视为 false。

上面返回!not其第一个参数 len 的布尔值 - 如果参数包含 0 以外的任意数量的字符,则返回 0,否则,如果根本没有字符,则返回 1。[ -n "$var" ]基本上,这与您可以使用 执行的测试相同,但它只是将其包装在一个名为 的小函数中bool()

这通常是如何旗帜可变的作品。例如:

[ -d "$dir" ] || dir=

脚本的其他部分只需要查找任何值即可$dir衡量其有用性。这在涉及参数替换时也很方便 - 因为参数可以扩展到默认值以填充空或未设置的参数,但否则会扩展到预设值,例如...

for set in yes ''
do echo "${set:-unset or null}"
done

...这会打印...

yes
unset or null

当然,也可以做相反的事情:+,但这只能给你一个预设的默认值或根本不给你任何东西,而上面的形式可以给你一个值或默认值。

因此,关于这三种选择 - 任何一种都可以工作,具体取决于您选择如何实施它。该函数的返回是自测试的,但是,如果该返回因任何原因需要保存,则需要将其放入变量中。这取决于用例 - 是您希望一次评估测试并完成类型的布尔值吗?如果是这样,请执行该功能,否则可能需要其他两个中的一个。

答案2

每个bash变量本质上都是一个字符串(或者一个数组或一个函数,但我们在这里讨论常规变量)。

条件是根据测试命令的返回值进行解析的——返回值不是变量,而是退出状态。当您评估if [ ... ]orif [[ ]]if grep something或类似的东西时,返回值 0(不是字符串 0,而是退出状态 0 = 成功)表示 true,其余表示 false(因此,与您在编译编程语言中习惯的完全相反,但由于成功的方式有一种,失败的方式也有很多种,并且执行的预期结果通常是成功,因此如果没有出现任何问题,则使用 0 作为最常见的默认结果)。这非常有用,因为任何二进制文件都可以用作测试 - 如果失败,则为 false,否则为 true。

true程序false(通常被内置程序覆盖)只是有用的小程序,不执行任何操作 -true成功执行任何操作,并以 0 退出,而false尝试不执行任何操作并“失败”,以 1 退出。听起来毫无意义,但对于脚本编写来说非常方便。

至于如何传递真实,就看你自己了。仅使用“y”或“yes”来表示真实性和使用是很常见的if [ x"$variable" = x"yes" ](附加虚拟字符串,x因为如果$variable碰巧长度为零,这可以防止创建if [ = "yes" ]无法解析的虚假命令)。简单地使用空字符串表示 false 并用于[ -z "$variable ]测试它是否为零长度(或-n是否为非零)也可能很有用。

不管怎样,实际上很少需要传递布尔值bash——更常见的是简单地exit失败,或者返回一个有用的结果(或者如果出现问题则返回零,并测试空字符串),并且大多数情况都可以直接从退出状态测试失败。


在您的情况下,您需要一个充当任何其他命令的函数(因此,成功时返回 0),因此您的最后一个选项似乎是正确的选择。

另外,您甚至可能不需要return语句。如果函数足够简单,您可以使用它仅返回函数中最后执行的命令的状态这一事实。因此您的函数可以简单地

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

如果您正在测试设备节点是否存在(或 grep/proc/mounts检查它是否已安装?)。

答案3

基本上任何非 0 的数字都是 true,0 都是 false。返回值 0 表示脚本成功结束的原因,或返回任何其他数字来标识不同类型的错误的原因。

$?将返回上一个命令/可执行文件的退出代码,0 成功,任何其他数字表示已返回的错误。

所以我会使用该方法来判断真/假。if (( ! $? ));then OK;else NOOK;fi

相关内容