我尝试在shell脚本中使用以下语法声明一个布尔变量:
variable=$false
variable=$true
这对吗?另外,如果我想更新这个变量,我会使用相同的语法吗?最后,下面使用布尔变量作为表达式的语法正确吗?
if [ $variable ]
if [ !$variable ]
我尝试在shell脚本中使用以下语法声明一个布尔变量:
variable=$false
variable=$true
这对吗?另外,如果我想更新这个变量,我会使用相同的语法吗?最后,下面使用布尔变量作为表达式的语法正确吗?
if [ $variable ]
if [ !$variable ]
当前回答
以下是对miku原始答案的改进,解决了Dennis Williamson对未设置变量的情况的担忧:
the_world_is_flat=true
if ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
测试变量是否为false:
if ! ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
关于变量中有讨厌内容的其他情况,这是任何外部输入馈送到程序的问题。
任何外部输入都必须在信任它之前进行验证。但是,当接收到输入时,这种验证只需要执行一次。
它不必像Dennis Williamson建议的那样,每次使用变量都这样做,从而影响程序的性能。
其他回答
长话短说:
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 ...
修正答案(2014年2月12日)
the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
echo 'Be careful not to fall off!'
fi
原来的答案
警告:https://stackoverflow.com/a/21210966/89391
the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
echo 'Be careful not to fall off!'
fi
来自:在Bash中使用布尔变量
此处包含原答案的原因是,2014年2月12日修改前的评论仅涉及原答案,许多评论与修改后的答案相关联时是错误的。例如,Dennis Williamson在2010年6月2日关于bash builtin true的评论只适用于原始答案,而不适用于修改后的答案。
我如何在shell脚本中声明和使用布尔变量?
与许多其他编程语言不同,Bash不按“类型”隔离其变量。[1]
所以答案很明确。在Bash中没有任何布尔变量。
然而:
使用declare语句,可以将赋值限制为 变量。[2]
#!/bin/bash
declare -ir BOOL=(0 1) # Remember BOOL can't be unset till this shell terminates
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}
# Same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"
declare和readonly中的r选项用于显式声明变量为只读。我希望目的很明确。
这是一个关于在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
这里似乎有一些关于Bash内置true的误解,更具体地说,关于Bash如何展开和解释括号内的表达式的误解。
miku回答中的代码与Bash内置的true,或/bin/true,或任何其他类型的true命令完全无关。在这种情况下,true只不过是一个简单的字符串,并且没有调用true命令/内置,无论是通过变量赋值,还是通过条件表达式求值。
下面的代码在功能上与miku回答中的代码相同:
the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
echo 'Be careful not to fall off!'
fi
唯一不同的是,这里比较的四个字符是'y'、'e'、'a'和'h',而不是't'、'r'、'u'和'e'。就是这样。在Bash解析令牌true时,没有尝试调用名为yeah的命令或内置命令,(在miku的例子中)也没有任何特殊处理。它只是一个字符串,一个完全任意的字符串。
更新(2014-02-19):在看了miku回答中的链接后,现在我知道困惑来自哪里了。Miku的回答使用了单括号,但他链接的代码片段没有使用括号。它只是:
the_world_is_flat=true
if $the_world_is_flat; then
echo 'Be careful not to fall off!'
fi
这两个代码段将以相同的方式运行,但括号完全改变了底层的内容。
以下是Bash在每种情况下所做的事情:
没有括号:
将变量$the_world_is_flat展开为字符串“true”。 尝试将字符串“true”解析为命令。 找到并运行true命令(内置或/bin/true,取决于Bash版本)。 比较true命令的退出码(总是0)和0。回想一下,在大多数shell中,退出码为0表示成功,其他任何退出码都表示失败。 因为退出代码是0 (success),所以执行if语句的then子句
括号:
将变量$the_world_is_flat展开为字符串“true”。 解析现在完全展开的条件表达式,其形式为string1 = string2。=操作符是bash的字符串比较操作符。所以… 对"true"和"true"进行字符串比较。 是的,这两个字符串是一样的,所以条件的值为真。 执行if语句的then子句。
不带括号的代码可以工作,因为true命令返回一个退出代码0,表示成功。括号内的代码可以工作,因为$the_world_is_flat的值与=右边的字符串字面量true相同。
为了说明这一点,请考虑以下两段代码:
这段代码(如果以root权限运行)将重启您的计算机:
var=reboot
if $var; then
echo 'Muahahaha! You are going down!'
fi
这段代码只是打印出“Nice try”。没有调用reboot命令。
var=reboot
if [ $var ]; then
echo 'Nice try.'
fi
更新(2014-04-14)回答评论中关于=和==的区别的问题:AFAIK,没有区别。==操作符是特定于bash的=的同义词,据我所知,它们在所有上下文中的工作方式完全相同。
但是请注意,我特别讨论的是[]或[[]]测试中使用的=和==字符串比较运算符。我并不是说=和==在bash中到处都可以互换。
例如,你显然不能用==来做变量赋值,比如var=="foo"(技术上你可以这样做,但var的值将是"=foo",因为Bash在这里没有看到==运算符,它看到的是=(赋值)运算符,后面跟着字面值="foo",这就变成了"=foo")。
此外,虽然=和==是可互换的,但您应该记住,这些测试的工作方式取决于您是否在[]或[[]]中使用它,以及操作数是否被引用。您可以在高级Bash脚本指南:7.3其他比较操作符(向下滚动到=和==的讨论)中阅读更多相关内容。