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

variable=$false

variable=$true

这对吗?另外,如果我想更新这个变量,我会使用相同的语法吗?最后,下面使用布尔变量作为表达式的语法正确吗?

if [ $variable ]

if [ !$variable ]

当前回答

博士TL;

my_bool=true

if [ "$my_bool" = true ]

未来音乐(最初)的回答有问题

我不推荐公认的答案。它的语法很漂亮,但也有一些缺陷。

假设我们有以下条件。

if $var; then
  echo 'Muahahaha!'
fi

在以下情况2中,此条件将计算为true并执行嵌套命令。

# Variable var not defined beforehand. Case 1
var=''  # Equivalent to var="".      # Case 2
var=                                 # Case 3
unset var                            # Case 4
var='<some valid command>'           # Case 5

通常,当你的“布尔”变量var显式设置为true时,你只希望你的条件值为true。其他所有的案例都是危险的误导!

最后一种情况(#5)特别淘气,因为它将执行变量中包含的命令(这就是为什么对于有效的command3,4,条件的计算结果为true)。

这里有一个无害的例子:

var='echo this text will be displayed when the condition is evaluated'
if $var; then
  echo 'Muahahaha!'
fi

# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!

引用你的变量是更安全的,例如,if "$var";然后。在上述情况下,您应该得到一个警告,表示没有找到该命令。但我们仍然可以做得更好(见下面我的建议)。

也可以看看Mike Holt对Miku最初答案的解释。

赫巴的回答有问题

这种方法也有意想不到的行为。

var=false
if [ $var ]; then
  echo "This won't print, var is false!"
fi

# Outputs:
# This won't print, var is false!

您可能期望上述条件的值为false,因此永远不会执行嵌套语句。惊喜!

引用值("false"),引用变量("$var"),或者使用test或[[而不是[,都没有区别。

我的建议是:

以下是我建议你检查“布尔值”的方法。他们按照预期工作。

my_bool=true

if [ "$my_bool" = true ]; then
if [ "$my_bool" = "true" ]; then

if [[ "$my_bool" = true ]]; then
if [[ "$my_bool" = "true" ]]; then
if [[ "$my_bool" == true ]]; then
if [[ "$my_bool" == "true" ]]; then

if test "$my_bool" = true; then
if test "$my_bool" = "true"; then

它们几乎都是一样的。与其他答案5中的方法相比,您将不得不输入更多的按键,但您的代码将更具防御性。


脚注

未来音乐的回答已被编辑,不再包含(已知的)缺陷。 这不是一个详尽的清单。 在此上下文中,有效命令是指存在的命令。命令使用正确或不正确并不重要。例如,man woman仍然被认为是一个有效的命令,即使没有这样的手册页存在。 对于无效的(不存在的)命令,Bash只会报错说没有找到该命令。 如果你关心长度,第一个建议是最短的。

其他回答

这是一个关于在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

POSIX(便携式操作系统接口)

我忽略了关键的一点,那就是便携性。这就是为什么我的头文件本身有POSIX。

基本上,所有投票的答案都是正确的,除了它们太特定于bash之外。

基本上,我只想添加更多关于可移植性的信息。


像["$var" = true]中的[和]括号是不必要的,你可以省略它们,直接使用test命令: test "$var" = true && yourCodeIfTrue || yourCodeIfFalse 重要提示:我不再推荐这种方法,因为它正在慢慢被弃用,而且组合多个语句更加困难。 想象一下这些单词true和false对shell意味着什么,自己测试一下: Echo $((true)) 0 Echo $((false)) 1 但是使用引号: Echo $(("true")) Bash: "true":语法错误:操作数预期(错误令牌是"true") Sh(破折号):Sh: 1:算术表达式:期望主:""true"" 这同样适用于: Echo $(("false")) shell只能解释一个字符串。我希望你的想法是多么好的使用适当的关键字没有引号。 但在之前的回答中没有人这么说。 这是什么意思?嗯,有几件事。 你应该习惯布尔关键字实际上被视为数字,即true = 0和false = 1,记住所有非零值都被视为false。 因为它们被视为数字,你也应该这样对待它们,即如果你定义变量说: var_bool = true 回声“var_bool美元” 真正的 你可以用以下方法创建它的相反值: Var_bool =$((1 - $ Var_bool)) #与$((!美元var_bool)) 回声“var_bool美元” 1 正如您自己所看到的,shell在您第一次使用它时确实打印了true字符串,但从那以后,它都分别通过数字0表示true或1表示false来工作。


最后,你应该如何处理所有这些信息

首先,一个好习惯是赋值0而不是true;1而不是false。 第二个好习惯是测试变量是否等于0: If ["$var_bool" -eq 0];然后 yourCodeIfTrue 其他的 yourCodeIfFalse fi

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

足够简单并且没有依赖项。

长话短说:

Bash中没有布尔值

true和false命令

Bash确实有比较和条件方面的布尔表达式。也就是说,在Bash中可以声明和比较的是字符串和数字。就是这样。

无论你在Bash中看到真或假,它要么是一个字符串,要么是一个命令/内置,它只用于退出代码。

这语法…

if true; then ...

本质上是…

if COMMAND; then ...

其中命令为true。当命令返回退出代码0时,条件为真。true和false是Bash内置的,有时也是独立的程序,它们什么都不做,只返回相应的退出码。


条件在if..then..fi

当使用方括号或test命令时,您依赖于该构造的退出代码。请记住,[]和[[]]也像其他命令一样只是命令/内置程序。所以…

if [[ 1 == 1 ]]; then echo yes; fi

对应于

if COMMAND; then echo yes; fi

这里的COMMAND是[[参数为1 == 1]]

如果…那么…Fi构念只是语法糖。你可以用双&号分隔命令来运行同样的效果:

[[ 1 == 1 ]] && echo yes

当在这些测试结构中使用true和false时,您实际上只是将字符串“true”或“false”传递给测试命令。这里有一个例子:

信不信由你,但这些条件都产生了相同的结果:

if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...

TL,博士;总是与字符串或数字进行比较

为了让未来的读者更清楚地了解这一点,我建议在真假周围使用引号:

DO

if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ "${var}" == "yes" ]]; then ...
if [[ "${var}" == "USE_FEATURE_X" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

# Always use double square brackets in bash!
if [ ... ]; then ...
# This is not as clear or searchable as -n
if [[ "${var}" ]]; then ...
# Creates impression of Booleans
if [[ "${var}" != true ]]; then ...
# `-eq` is for numbers and doesn't read as easy as `==`
if [[ "${var}" -eq "true" ]]; then ...

也许

# Creates impression of Booleans.
# It can be used for strict checking of dangerous operations.
# This condition is false for anything but the literal string "true".
if [[ "${var}" != "true" ]]; then ... 

下面是一个适合我的简单例子:

temp1=true
temp2=false

if [ "$temp1" = true ] || [ "$temp2" = true ]
then
    echo "Do something." 
else
    echo "Do something else."
fi