协慌网

登录 贡献 社区

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

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

variable=$false

variable=$true

它是否正确?另外,如果我想更新该变量,我会使用相同的语法吗?最后,使用布尔变量作为正确的表达式是以下语法:

if [ $variable ]

if [ !$variable ]

答案

修订回答(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

From: 在 Bash 中使用布尔变量

这里包含原始答案的原因是因为 2014 年 2 月 12 日修订前的评论仅适用于原始答案,并且许多评论在与修订后的答案相关时是错误的。例如,丹尼斯 · 威廉姆森的有关 bash 的评论内置true在 2010 年 6 月 2 日只适用于原有的答案,而不是修改。

TL; DR

bool=true

if [ "$bool" = true ]

Miku( 原创 )答案的问题

推荐接受的答案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

通常,当您的 “boolean” 变量(在此示例中为var )显式设置为 true 时,您只希望将条件计算为 true。所有其他案件都具有危险的误导性!

最后一种情况(#5)尤其顽皮,因为它将执行变量中包含的命令(这就是为什么条件对于有效命令3,4评估为真的原因)。

这是一个无害的例子:

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但你的代码将更具防御性。


脚注

  1. Miku 的答案已被编辑,不再包含(已知)缺陷。
  2. 不是一个详尽的清单。
  3. 此上下文中的有效命令表示存在的命令。如果正确或错误地使用命令并不重要。例如,即使没有这样的手册页, man woman仍将被视为有效命令。
  4. 对于无效(不存在)命令,Bash 只会抱怨找不到命令。
  5. 如果你关心长度,第一个建议是最短的。

这里似乎存在一些误解,关于 Bash 内置的true ,更具体地说,关于 Bash 如何扩展和解释括号内的表达式。

miku 的答案中的代码与 Bash builtin true ,nor /bin/true以及true命令的任何其他风格完全无关。在这种情况下, true只不过是一个简单的字符串,并且不会通过变量赋值或条件表达式的求值来调用true命令 / builtin。

以下代码在功能上与 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'。而已。没有尝试调用命令或内置命名为yeah ,也没有(在 miku 的例子中)当 Bash 解析令牌为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 在每种情况下所做的事情:

没有括号:

  1. 将变量$the_world_is_flat扩展为字符串"true"
  2. 尝试将字符串"true"解析为命令。
  3. 查找并运行true命令(内置或/bin/true ,具体取决于 Bash 版本)。
  4. true命令的退出代码(始终为 0)与 0 进行比较。回想一下,在大多数 shell 中,退出代码为 0 表示成功,其他任何表示失败。
  5. 由于退出代码为 0(成功),执行if语句的then子句

括号:

  1. 将变量$the_world_is_flat扩展为字符串"true"
  2. 解析现在完全展开的条件表达式,其形式为string1 = string2=运算符是 bash 的字符串比较运算符 。所以...
  3. "true""true"进行字符串比较。
  4. 是的,这两个字符串是相同的,所以条件的值是真的。
  5. 执行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" )。

此外,虽然===是可以互换的,但你应该记住,这些测试的工作方式取决于你是在[ ][[ ]]使用它,还是取决于是否引用了操作数。您可以在Advanced Bash Scripting Guide 中阅读更多相关内容:7.3 其他比较运算符 (向下滚动到===的讨论)。