为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

芜湖不芜 2019-11-04 14:52:01
我尝试使用以下语法在Shell脚本中声明布尔变量:variable=$falsevariable=$true这个对吗?另外,如果我想更新该变量,我会使用相同的语法吗?最后,使用布尔变量作为表达式的以下语法正确吗?if [ $variable ]
查看完整描述

3 回答

?
达令说

TA贡献1821条经验 获得超6个赞

bool=true


if [ "$bool" = true ]

有三苦的(问题原)答案

我不推荐接受的答案1。它的语法很漂亮,但是有一些缺陷。


说我们有以下情况。


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)特别顽皮,因为它将执行变量中包含的命令(这就是为什么条件对于有效命令3、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"; then。在上述情况下,您应该得到一条警告,提示找不到该命令。但是我们仍然可以做得更好(请参阅底部的建议)。


另请参阅Mike Holt对Miku原始答案的解释。


Hbar的答案有问题

这种方法也具有意外的行为。


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或[[代替[都没有区别。


我的建议:

我建议您通过以下方法检查“布尔值”。他们按预期工作。


bool=true


if [ "$bool" = true ]; then

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


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

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

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

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


if test "$bool" = true; then

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

它们几乎相等。您将需要比其他答案5中的方法键入更多的击键,但是您的代码将更具防御性。


脚注

此后,Miku的答案已被编辑,不再包含(已知)缺陷。

并非详尽的清单。

在此上下文中,有效命令表示存在的命令。命令的使用正确与否无关紧要。例如man woman,即使不存在这样的手册页,它也仍然被视为有效命令。

对于无效(不存在)的命令,Bash只会抱怨找不到该命令。

如果您在意长度,则第一个建议是最短的。


查看完整回答
反对 回复 2019-11-04
?
富国沪深

TA贡献1790条经验 获得超9个赞

关于Bash内置函数true,尤其是Bash如何扩展和解释方括号内的表达式,这里似乎存在一些误解。


miku的答案中的代码与内置的Bash true,nor /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”,并且代替“T”“H”,“R”,“U”,和“e”的。而已。yeah在Bash解析令牌时,没有尝试调用名为named的命令或内置命令,也没有进行任何形式的特殊处理(在miku的示例中)true。它只是一个字符串,并且完全是任意的。


更新(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(成功),因此执行if语句的then子句

括号:


将变量$the_world_is_flat扩展为字符串"true"。

解析现在已经扩展的条件表达式,其形式为string1 = string2。该=运算符是bash的字符串比较运算符。所以...

在"true"和上进行字符串比较"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”。重新启动命令不被调用。


var=reboot

if [ $var ]; then

  echo 'Nice try.'

fi

更新(2014年4月14日)要回答在评论有关之间的差异问题=和==:据我所知,没有任何区别。该==运营商特定的Bash-代名词=,而据我所看到的,他们的工作完全一样在所有上下文中。


但是请注意,我是专门讨论在或测试中使用的=和==字符串比较运算符。我不建议这样做,并且在bash中到处都是可以互换的。[ ][[ ]]===


例如,您显然不能使用进行变量赋值==,例如var=="foo"(从技术上讲,您可以这样做,但是varwill 的值是"=foo",因为Bash ==在这里没有看到运算符,而是看到了=(赋值)运算符,然后是文字值="foo",变成"=foo")。


另外,尽管=和==可以互换,但是您应该记住,这些测试的工作方式确实取决于您是在[ ]还是内部使用它[[ ]],还取决于是否引用了操作数。你可以阅读更多关于高级Bash脚本编程指南:7.3其他比较操作符(向下滚动到的讨论=和==)。


查看完整回答
反对 回复 2019-11-04
  • 3 回答
  • 0 关注
  • 2759 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信