我想尝试简单的脚本
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
(字符串),并且在某些情况下,该文本可能被解释为整数(1
、0xa
、010
等)。
因此,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))
那将改变flag
或0
的值1
。
笔记: 请检查是否有错误https://www.shellcheck.net/在将代码作为问题发布之前,很多时候这足以找到问题。