如何在shell脚本中声明和使用布尔变量?

1443

我试着在Shell脚本中使用以下语法声明一个布尔变量:

variable=$false

variable=$true

这是正确的吗?如果我想要更新那个变量,我会使用相同的语法吗?最后,使用布尔变量作为表达式的以下语法是否正确?

if [ $variable ]

if [ !$variable ]
27个回答

1
我发现现有的答案很令人困惑。
就个人而言,我只想要一个看起来和工作方式类似于C的东西。
这段代码每天在生产中运行多次:
snapshotEvents=true

if ($snapshotEvents)
then
    # Do stuff if true
fi

为了让每个人都满意,我测试了:

snapshotEvents=false

if !($snapshotEvents)
then
    # Do stuff if false
fi

这也很好地工作了。

$snapshotEvents 评估变量值的内容。因此,您需要 $

您实际上不需要括号,我只是觉得它们有帮助。


2
当您删除括号时,这正是@miku在顶部的原始答案。 - dolmen
1
没有括号,表达式就无法求值。 - will
@will 是的,它可以。你不需要使用()。 - phil294
1
@Blauhirn...你好,我的评论是基于在Linux Mint/Ubuntu PC上使用GNU Bash进行的实验。理论上来说,您可能是正确的,()不是必需的。但是我的回应是,请尝试一下,这似乎取决于Bash版本、实际表达式或上下文等因素。 - will
这显然(对我来说)是最清晰的语法,但肯定有什么地方出了问题。我认为它不能用于整数值:`> bucket_available=0;
if ($bucket_available); then echo hi; fi bash: 0: command not found`
- Max Cascone

1
你可以使用shFlags
它让你有定义选项:DEFINE_bool 例如:
DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");

从命令行可以定义:

sh script.sh --bigmenu
sh script.sh --nobigmenu # False

1
GFlags在这个答案中没有意义 - 它是一个C++库。它不能直接用于shell脚本。 - Jonathan Cross
更新了对shFlags的响应,它是GFlags到shell的一个端口。 - gogasca

1
这是一个有关在Bash中测试“布尔”值的不同方法的速度测试:
#!/bin/bash
rounds=100000

b=true # For true; b=false for false
type -a true
time for i in $(seq $rounds); do command $b; done
time for i in $(seq $rounds); do $b; done
time for i in $(seq $rounds); do [ "$b" == true ]; done
time for i in $(seq $rounds); do test "$b" == true; done
time for i in $(seq $rounds); do [[ $b == true ]]; done

b=x; # Or any non-null string for true; b='' for false
time for i in $(seq $rounds); do [ "$b" ]; done
time for i in $(seq $rounds); do [[ $b ]]; done

b=1 # Or any non-zero integer for true; b=0 for false
time for i in $(seq $rounds); do ((b)); done

它会打印出类似这样的内容。
true is a shell builtin
true is /bin/true

real    0m0,815s
user    0m0,767s
sys     0m0,029s

real    0m0,562s
user    0m0,509s
sys     0m0,022s

real    0m0,829s
user    0m0,782s
sys     0m0,008s

real    0m0,782s
user    0m0,730s
sys     0m0,015s

real    0m0,402s
user    0m0,391s
sys     0m0,006s

real    0m0,668s
user    0m0,633s
sys     0m0,008s

real    0m0,344s
user    0m0,311s
sys     0m0,016s

real    0m0,367s
user    0m0,347s
sys     0m0,017s

1
其他答案非常慢。
不要检查布尔变量是否等于任何值,而是检查它是否为空或非空。
#false:
condition=""

#true:
condition=x

#check:
[ -n "${condition}" ]

0
[[ "$x" == 'true' || "$x" -ne 0 ]] && ...

非常简单,没有依赖关系。


-1

Bash真的让人感到困惑,因为它有像[[[(($((等等这样的东西。

所有这些都占用了彼此的代码空间。我猜这主要是历史原因,Bash有时必须假装成sh

大多数情况下,我可以选择一种方法并坚持使用它。在这种情况下,我倾向于声明(最好是在一个通用库文件中,我可以在我的实际脚本中使用.包含它)。

TRUE=1; FALSE=0

然后我可以使用 (( ... )) 算术运算符进行测试。

testvar=$FALSE

if [[ -d ${does_directory_exist} ]]
then
    testvar=$TRUE;
fi

if (( testvar == TRUE )); then
    # Do stuff because the directory does exist
fi
  1. 你必须要有纪律性。你的 testvar 必须一直设置为 $TRUE 或者 $FALSE

  2. (( ... )) 比较中,不需要使用前导符号 $,这样更易读。

  3. 我可以使用 (( ... )),因为 $TRUE=1$FALSE=0,即数值。

  4. 缺点是有时候需要使用 $

    testvar=$TRUE
    

    这不太好看。

这不是一个完美的解决方案,但它涵盖了我需要进行此类测试的每种情况。


2
你应该将常量声明为只读。同时,在使用变量时,请始终使用花括号。这是每个人都应该遵循的惯例。这种解决方案的一个大缺点是,您不能将代数表达式与测试标志或字符串比较混合使用。 - Hubert Grzeskowiak

-2

替代方案 - 使用函数

is_ok(){ :;}
is_ok(){ return 1;}
is_ok && echo "It's OK" || echo "Something's wrong"

定义函数不太直观,但检查其返回值非常容易。


1
这不是一个你可以测试的变量,而是一个常数函数。 - jarno
@jarno 对于脚本的目的,测试函数的返回值与测试变量有何不同? - johnraff
好的,这个问题是关于变量的。 - jarno
True,虽然在shell脚本中的使用方式是相同的。 - johnraff

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