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


15

我知道,中有布尔值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
    }
    

我最想知道的是,其他想要使用包装器的人会期望什么。他们期望布尔值,像变量这样的命令或要调用的函数吗?

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


3
help true ; help false ; help exit
Costas 2015年

3
@Costas您介意吗?
Minix

Answers:


2
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

当然,也可以执行相反的操作,:+但这只能给您预设的默认值或什么都不提供,而上述形式可以给您一个值或默认值。

因此,关于这三个选择-任何一个都可以根据您选择的实现方式来起作用。该函数的返回值是自检的,但是,如果该返回值出于任何原因需要保存,则需要将其放入变量中。这取决于用例-您是否希望对测试进行一次评估并完成的布尔值类型?如果是这样,请执行此功能,否则可能需要另外两个。


1
我不认为您在回答我的问题。我不是在问如何在shell脚本中使用布尔值,而是哪种方法是最常见的,并且会被另一个用户期望。如果我的问题不清楚,我很乐意对其进行编辑。对于您的答案所做的简短解释也不错。谢谢。
Minix 2015年

@Minix更好吗?
mikeserv

我通常分配true或分配false一个变量,然后就可以执行if $variable; then ...
wurtel

@wurtel-依赖于默认值$IFS-如果var的值可能包含任何类型的用户输入,那么也很幸运。如果不知道该值开头,则几乎不需要对其进行测试。使用if ${var:+":"} false; thenw / boolean null / not null值时,您可以更安全地进行操作。但这几乎没有比[ -n "$var" ] &&
mikeserv 2015年

如果我variable=false以什么开始我的脚本,然后根据任何条件将其设置为true(就像我在C语言中使用变量时一样),那么就没有问题,无论如何,您对IFS值和随机变量值的变化有何痴迷。 。
wurtel

4

bash每一个变量本质上是一个字符串(或数组或函数,但让我们来谈谈常规变量这里)。

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

truefalse程序(通常由内置程序重写)只是有用的小程序,它们什么都不做- 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以检查是否已安装?)。


这是一个非常好的摘要,感谢您抽出宝贵的时间来编写它。我可以从您的最后一段中推断出,您会认为的选择drive_xyz_available()是最常见的吗?
Minix

您能提供一些常见y = true案例的例子吗?以我的经验,大多数包装器脚本都会测试任何非null值,以将其视为真-至少在涉及解释的环境变量的地方。否则,他们将完全不理会带壳汽车。
mikeserv

3
if如果用引号将该变量引起来,则不需要测试的虚拟字符串;if [ "$variable" = "yes" ]即使未设置$ variable也可以正常工作。
丹尼尔·库尔曼

-2

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

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

因此,我会将该方法用于true / false。 if (( ! $? ));then OK;else NOOK;fi


然后,我为最后一个选择写一个。谢谢。
Minix 2015年

5
非零数字实际上为假,零为真。只是看的输出true; echo $?false; echo $?
Ruslan 2015年

@Ruslan。您是否检查了我的命令的输出?我想你没有,否则你不会说你做了什么。0为假,其他任何数字为真,原因是取!反结果为TRUE。命令正确完成后的结果为0,并不意味着0为真。单词true可能是0,但0永远不会是真的,因为if条件表明。
YoMismo 2015年

这等于说,在C / C ++,0true因为if(!x){True();}else{False();}将调用True()x==0。但是正确的检查不是!x,而是!!x
Ruslan

你错了。我不是在说您写了什么以及该命令有什么顺序,if我只是声明一个事实,即在C / C ++中,在bash,ksh,tsh或...中,0为FALSE,任何其他数字为TRUE,如您在下面的链接中所读,C的初始实现未提供布尔类型,被定义为int,其中0为FALSE,1为TRUE en.wikipedia.org/wiki/Boolean_data_type
YoMismo 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.