我尝试在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建议的那样,每次使用变量都这样做,从而影响程序的性能。
其他回答
我发现现有的答案令人困惑。
就我个人而言,我只是想要一些看起来和工作起来像C的东西。
这段代码在生产中每天工作多次:
snapshotEvents=true
if ($snapshotEvents)
then
# Do stuff if true
fi
为了让大家开心,我测试了:
snapshotEvents=false
if !($snapshotEvents)
then
# Do stuff if false
fi
这也很有效。
$snapshotEvents计算变量value的内容。所以你需要$。
你们其实不需要括号,我只是觉得它们很有用。
在GNU Bash, version 4.1.11(2)-release上测试 Bash初学者指南,Machtelt Garrels, v1.11, 2008
Bash确实将问题与[,[[,((,$((等))等混淆了。
所有人都在践踏彼此的代码空间。我想这主要是历史原因,巴什不得不偶尔装成。
大多数时候,我可以选择一种方法并坚持下去。在这种情况下,我倾向于声明(最好是在我可以包含的公共库文件中)。在我的实际脚本(s))。
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
你必须遵守纪律。你的testvar必须在任何时候都被设置为$TRUE或$FALSE。 在(……))比较器,你不需要前面的$,这使得它更可读。 我可以用(…)),因为$TRUE=1和$FALSE=0,即数值。 缺点是不得不偶尔使用$: 真正testvar = $ 这可不太好。
这不是一个完美的解决方案,但它涵盖了我需要这种测试的所有情况。
与其伪造一个布尔值,给未来的读者留下一个陷阱,为什么不使用一个比真和假更好的值呢?
例如:
build_state=success
if something-horrible; then
build_state=failed
fi
if [[ "$build_state" == success ]]; then
echo go home; you are done
else
echo your head is on fire; run around in circles
fi
这里似乎有一些关于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其他比较操作符(向下滚动到=和==的讨论)中阅读更多相关内容。
长话短说:
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 ...