shell Bash中没有布尔变量 flag=0,flag=1
反转布尔变量
我想尝试简单的脚本
flag=false
while !$flag
do
read x
if [ "$x" -eq "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
但是,当我运行它时,如果键入true
,我会看到x="true"
和flag="true"
,但是循环并没有结束。脚本有什么问题?如何正确地将布尔变量取反?
Answers:
您的脚本中有两个错误。首先,您需要在!
和之间留一个空格$flag
,否则shell将寻找一个名为的命令!$flag
。第二个错误是-eq
用于整数比较,但是您正在字符串上使用它。根据您的外壳,您可能会看到错误消息,并且由于条件[ "$x" -eq "true" ]
不能为真,循环将永远继续,或者如果您输入任何字符串(包括false
),则每个非整数值都将被视为0,并且循环将退出不同于0的数字。
虽然! $flag
正确,但是将字符串视为命令是一个坏主意。可以,但是对脚本中的更改非常敏感,因为您需要确保该值$flag
只能是true
or 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
[
内置的ksh
,[ x -eq y ]
如果x
算术表达式解析为与y
算术表达式相同的数字,则返回true ,例如,x=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
将输出yes。
虽然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中都可以使用,但我没有感到惊讶,但是还没有检查标准。
! ! ((val))
可以像使用C或C ++一样在Bash中工作?例如,如果val
为0 ,则在之后仍为0 ! !
。如果val
为1,则之后为1 ! !
。如果val
为8,则在之后将其拉低至1 ! !
。还是我需要问另一个问题?
如果您完全可以确定该变量将包含0或1,则可以使用按位XOR等于运算符在两个值之间切换:
$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0
这对我有用:
flag=false
while [[ "$flag" == "false" ]]
do
read x
if [[ "$x" == "true" ]]
then
flag=true
fi
echo "${x} : ${flag}"
done
但是,实际上,您应该执行以下操作while
:
while ! $flag
Shell中没有布尔变量的概念。
shell变量只能是text
(一个字符串),并且,在某些情况下,该文本可以被解释为一个整数(1
,0xa
,010
等)。
因此,a flag=true
根本不暗示外壳的真实性或错误性。
串
可以执行的操作是字符串比较[ "$flag" == "true" ]
或在某些命令中使用变量内容并检查其结果,例如执行true
(因为同时存在true
一个被调用的可执行文件和一个被调用的可执行文件false
)作为命令,并检查该命令的退出代码是否为零(成功)。
$flag; if [ "$?" -eq 0 ]; then ... fi
或更短:
if "$flag"; then ... fi
如果将变量的内容用作!
命令,则如果两个(! cmd
)之间存在空格,则可以使用a 取反命令的退出状态,如下所示:
if ! "$flag"; then ... fi
该脚本应更改为:
flag=false
while ! "$flag"
do
read x
if [ "$x" == "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
整数
使用数值和算术扩展。
在这种情况下,$((0))
is 1
的退出代码和$((1))
is 的退出代码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/中的错误,这足以发现问题。
until
的缩写while !
(与Bourne until
相反!
),因此您可以执行以下操作:
flag=false
until "$flag"
do
IFS= read -r x
if [ "$x" = true ]
then
flag=true
fi
printf '%s\n' "$x : $flag"
done
哪个应该和:
flag=false
while ! "$flag"
do
IFS= read -r x
if [ "$x" = true ]
then
flag=true
fi
printf '%s\n' "$x : $flag"
done
您也可以将其编写为:
until
IFS= read -r x
printf '%s\n' "$x"
[ "$x" = true ]
do
continue
done
until
/ while
和之间的部分do
不必是单个命令。
!
是POSIX Shell语法中的关键字。它需要定界,令牌与后面的令牌分开,并且是管道之前的第一个令牌(! foo | bar
否定管道,foo | ! bar
尽管某些外壳程序接受它为扩展名,但它还是无效的)。
!true
被解释为!true
不太可能存在的命令。! true
应该管用。!(true)
应该在符合POSIX的炮弹工作作为!
作为它的后面是分隔的(
道理,但在实践中它并不在工作ksh
/ bash -O extglob
在那里与冲突!(pattern)
扩展水珠运营商也不zsh的在那里它与冲突(除SH仿真)glob(qualifiers)
与bareglobqual
和glob(group)
没有。
[ ${FOO:-0} == 0 ] && FOO=1 || FOO=0
甚至:
[ ${FOO:-false} == false ] && FOO=true || FOO=false
应该做的工作
https://qastack.cn/unix/24500/invert-boolean-variable#:~:text=Shell%E4%B8%AD%E6%B2%A1%E6%9C%89%E5%B8%83%E5%B0%94%E5%8F%98%E9%87%8F%E7%9A%84%E6%A6%82%E5%BF%B5%E3%80%82%20shell%E5%8F%98%E9%87%8F%E5%8F%AA%E8%83%BD%E6%98%AF%20text%20%EF%BC%88%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%89%EF%BC%8C%E5%B9%B6%E4%B8%94%EF%BC%8C%E5%9C%A8%E6%9F%90%E4%BA%9B%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E8%AF%A5%E6%96%87%E6%9C%AC%E5%8F%AF%E4%BB%A5%E8%A2%AB%E8%A7%A3%E9%87%8A%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%95%B4%E6%95%B0%EF%BC%88%201,%EF%BC%8C%200xa%20%EF%BC%8C%20010%20%E7%AD%89%EF%BC%89%E3%80%82