细绳

细绳

我想尝试简单的脚本

flag=false
while !$flag
do
   read x
   if [ "$x" -eq "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

但是当我运行它时,如果我输入true,我会看到x="true"flag="true",但循环并没有结束。脚本有什么问题?如何正确反转布尔变量?

答案1

您的脚本中有两个错误。第一个是!和之间需要有一个空格$flag,否则 shell 会查找名为 的命令!$flag。第二个错误是-eq用于整数比较,但您在字符串上使用它。根据您的 shell,您可能会看到一条错误消息,并且循环将永远继续下去,因为条件不可能为真,或者每个非整数值将被视为 0,并且如果您输入任何字符串(包括)[ "$x" -eq "true" ],循环将退出false除 0 以外的数字。

虽然! $flag这是正确的,但将字符串视为命令是一个坏主意。它会起作用,但它对脚本中的更改非常敏感,因为您需要确保它$flag永远不会是除了true或 之外的任何东西false。最好在这里使用字符串比较,就像下面的测试一样。

flag=false
while [ "$flag" != "true" ]
do
   read x
   if [ "$x" = "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

可能有更好的方法来表达您所追求的逻辑。例如,您可以创建一个无限循环,并在检测到终止条件时中断它。

while true; do
  read -r x
  if [ "$x" = "true" ]; then break; fi
  echo "$x: false"
done

答案2

虽然 Bash 中没有布尔变量,但使用算术评估来模拟它们非常容易。

flag= # False
flag=0 # False
flag=1 # True (actually any integer number != 0 will do, but see remark below about toggling)
flag="some string" # Maybe False (make sure that the string isn't interpreted as a number)

if ((flag)) # Test for True
then
  : # do something
fi

if ! ((flag)) # Test for False
then
  : # do something
fi

flag=$((1-flag)) # Toggle flag (only works when flag is either empty or unset, 0, 1, or a string which doesn't represent a number)

这也适用于 ksh。如果它适用于所有 POSIX 兼容的 shell,我不会感到惊讶,但尚未检查标准。

答案3

如果您可以绝对确定该变量将包含 0 或 1,则可以使用按位异或等于运算符在两个值之间翻转:

$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0

答案4

shell 中没有布尔变量的概念。
Shell 变量只能是text(字符串),并且在某些情况下,该文本可能被解释为整数(10xa010等)。

因此,aflag=true对 shell 来说根本不意味着真实或虚假。

细绳

可以做的是字符串比较[ "$flag" == "true" ]或在某些命令中使用变量内容并检查其后果,就像执行true(因为既有一个名为 的可执行文件true,也有一个名为 的可执行false文件)作为命令,并检查该命令的退出代码是否为零(成功)。

$flag; if [ "$?" -eq 0 ]; then ... fi

或者更短:

if "$flag"; then ... fi

如果变量的内容用作命令,则 a!可用于否定命令的退出状态,前提是两者 ( ! cmd) 之间存在空格,如下所示:

if ! "$flag"; then ... fi

该脚本应更改为:

flag=false
while ! "$flag" 
do
   read x
   if [ "$x" == "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

整数

使用数值和算术扩展

在这种情况下, 的退出代码$((0))1, 的退出代码$((1))0
在 bash、ksh 和 zsh 中,算术可以在 a 内执行(注意缺少((..))开头)。$

flag=0; if ((flag)); then ... fi

此代码的可移植版本更加复杂:

flag=0; if [ "$((flag))" -eq 0 ]; then ... fi      # test for a number
flag=0; if [ "$((flag))"  == 0 ]; then ... fi      # test for the string "0"

在 bash/ksh/zsh 中你可以这样做:

flag=0    
while ((!flag)) 
do
   read x
   [ "$x" == "true" ] && flag=1
   echo "${x} : ${flag}"
done

或者

您可以“反转布尔变量”(前提是它包含数值):

((flag=!flag))

那将改变flag0的值1


笔记: 请检查是否有错误https://www.shellcheck.net/在将代码作为问题发布之前,很多时候这足以找到问题。

相关内容