我尝试使用以下语法在shell脚本中声明一个布尔变量:
variable=$false
variable=$true
这是对的吗?另外,如果我想更新该变量,我会使用相同的语法吗?最后,使用布尔变量作为正确的表达式是以下语法:
if [ $variable ]
if [ !$variable ]
答案 0 :(得分:961)
修订答案(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
来自:Using boolean variables in Bash
此处包含原始答案的原因是因为2014年2月12日修订前的评论仅适用于原始答案,并且许多评论在与修订后的答案相关时是错误的。例如,Dennis Williamson在2010年6月2日关于bash builtin true
的评论仅适用于原始答案,而非修订版。
答案 1 :(得分:684)
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
通常,只有当您的“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
。在上述情况下,您应该收到一条警告,指出找不到该命令。但我们仍然可以做得更好(请参阅我在底部的建议)。
Also see Mike Holt's explanation of Miku's original answer.
这种方法也有意想不到的行为。
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 中的方法,但你的代码会更具防御性。
man woman
仍将被视为有效命令。答案 2 :(得分:144)
这里似乎存在一些关于Bash内置true
的误解,更具体地说,关于Bash如何扩展和解释括号内的表达式。
miku's answer中的代码与Bash内置true
,/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在每种情况下所做的事情:
没有括号:
$the_world_is_flat
展开为字符串"true"
。"true"
解析为命令。true
命令(内置或/bin/true
,具体取决于Bash版本。)true
命令的退出代码(始终为0)与0进行比较。回想一下,在大多数shell中,退出代码0表示成功,其他任何表示失败。if
语句的then
子句<强>支架:强>
$the_world_is_flat
展开为字符串"true"
。string1 = string2
。 =
运算符是bash的字符串比较运算符。所以... "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”。不会调用reboot命令。
var=reboot
if [ $var ]; then
echo 'Nice try.'
fi
更新(2014-04-14)要回答有关=
和==
:AFAIK之间差异的评论中的问题,没有区别。 ==
运算符是=
的特定于Bash的同义词,据我所见,它们在所有上下文中的工作方式完全相同。
但请注意,我特别谈到=
或==
测试中使用的[ ]
和[[ ]]
字符串比较运算符。我不是建议在bash中=
和==
可以互换到处。
例如,您显然无法使用==
进行变量分配,例如var=="foo"
(技术上您可以执行此操作,但{{1}的值将var
,因为Bash在这里没有看到"=foo"
运算符,它看到==
(赋值)运算符,后跟文字值=
,只需变成="foo"
)。
此外,尽管"=foo"
和=
可以互换,但您应该记住这些测试的工作方式取决于您是否在{{1}内使用它}或==
,以及是否引用操作数。您可以在 Advanced Bash Scripting Guide: 7.3 Other Comparison Operators 中详细了解相关内容(向下滚动至[ ]
和[[ ]]
的讨论。)
答案 3 :(得分:45)
使用算术表达式。
#!/bin/bash
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
输出:
真
不是假的
答案 4 :(得分:24)
长话短说:
bash有什么,就比较和条件而言是布尔表达式。也就是说,你可以在bash中声明和比较的是字符串和数字。就是这样。
无论你在bash中看到true
还是false
,它都是字符串或命令/ builtin,它只用于退出代码。
这种语法......
if true; then ...
本质上是......
if COMMAND; then ...
只要命令返回退出代码0,条件就为真。true
和false
是Bash内置函数,有时也是独立程序,只返回相应的退出代码。
上述条件相当于:
COMMAND && ...
使用方括号或test
命令时,依赖于该构造的退出代码。请注意,[ ]
和[[ ]]
也只是其他命令/内置命令。所以...
if [[ 1 == 1 ]]; then echo yes; fi
对应
if COMMAND; then echo yes; fi
此处COMMAND
为[[ 1 == 1 ]]
if..then..fi
构造只是语法糖。您始终只需运行由双&符号分隔的命令即可获得相同的效果:
[[ 1 == 1 ]] && echo yes
在这些测试构造中使用true
和false
时,实际上只是将字符串"true"
或"false"
传递给测试命令。这是一个例子:
信不信由你,但这些条件都产生了相同的结果:
if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...
为了向未来的读者说明这一点,我建议您始终使用true
和false
周围的引号:
if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...
if [ ... ]; then ... # always use double square brackets in bash!
if [[ "${var}" ]]; then ... # this is not as clear or searchable as -n
if [[ "${var}" != true ]]; then ... # creates impression of booleans
if [[ "${var}" -eq "true" ]]; then ... # `-eq` is for numbers and doesn't read as easy as `==`
if [[ "${var}" != "true" ]]; then ... # creates impression of booleans. Can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".
答案 5 :(得分:15)
很久以前,当我们只有sh
时,通过依赖test
程序的约定处理布尔值,其中test
如果没有参数运行则返回错误的退出状态。这允许人们将未设置的变量视为false,将变量设置为任何值为true。今天,测试内置于bash
,并且通常以其一个字符别名[
(或者在没有它的shell中使用的可执行文件,如dolmen注释)而闻名:
FLAG="up or <set>"
if [ "$FLAG" ] ; then
echo 'Is true'
else
echo 'Is false'
fi
# unset FLAG
# also works
FLAG=
if [ "$FLAG" ] ; then
echo 'Continues true'
else
echo 'Turned false'
fi
由于引用约定,脚本编写者更喜欢使用模仿[[
但具有更好语法的复合命令test
:不需要引用带空格的变量,可以使用{{1} }和&&
作为具有奇怪优先级的逻辑运算符,并且对术语数量没有POSIX限制。
例如,要确定是否设置了FLAG且COUNT是否是大于1的数字:
||
This stuff can get confusing当需要空格,零长度字符串和空变量时,以及脚本需要使用多个shell时。
答案 6 :(得分:11)
如何在shell脚本中声明和使用布尔变量?
与许多其他编程语言不同,Bash不会将其变量按“类型”隔离。 [1]
所以答案非常明确。 bash中没有#!/bin/bash
declare -ir BOOL=(0 1) #remember BOOL can't be unset till this shell terminate
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}
#same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"
。
但是:
使用声明语句,我们可以将值赋值限制为变量。[2]
r
declare
和readonly
中的{{1}}选项用于明确声明变量只读。希望目的明确。
答案 7 :(得分:8)
为什么不使用比true和false更好的值,而不是伪造布尔值并为未来的读者留下陷阱?
例如:
build_state=success
if something-horrible; then
build_state=failed
fi
if [[ "$build_state" == success ]]; then
echo go home, you are done
else
echo your head is on fire, run around in circles
fi
答案 8 :(得分:3)
# setting ----------------
commonMode=false
if [[ $something == 'COMMON' ]]; then
commonMode=true
fi
# using ----------------
if $commonMode; then
echo 'YES, Common Mode'
else
echo 'NO, no Common Mode'
fi
$commonMode && echo 'commonMode is ON ++++++'
$commonMode || echo 'commonMode is OFF xxxxxx'
答案 9 :(得分:3)
Bill Parker is getting voted down,因为他的定义与正常的代码约定相反。通常,true定义为0,false定义为非零。 1将用于false,9999和-1也是如此。与函数返回值相同 - 0表示成功,任何非零表示失败。对不起,我没有街头信誉可以投票或直接回复。
Bash建议现在使用双括号作为习惯而不是单个括号,Mike Holt给出的链接解释了它们如何工作的差异。 7.3. Other Comparison Operators
首先,-eq
是一个数值运算符,因此需要代码
#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
将发出错误语句,期望一个整数表达式。这适用于任一参数,因为它们都不是整数值。然而,如果我们在它周围放置双括号,它将不会发出错误声明,但它会产生错误的值(嗯,在50%的可能排列中)。它将评估为[[0 -eq true]] =成功,但也会[[0 -eq false]] =成功,这是错误的(嗯....那个内置数字值是什么?)。< / p>
#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
条件的其他排列也会产生错误的输出。基本上,将变量设置为数值并将其与true / false内置值进行比较,或将变量设置为true / false内置并将其与数值进行比较的任何事物(上面列出的错误条件除外)。此外,任何将变量设置为true / false内置并使用-eq
进行比较的内容。因此,请避免-eq
进行布尔比较,并避免使用数值进行布尔比较。以下是将产生无效结果的排列摘要:
#With variable set as an integer and evaluating to true/false
#*** This will issue error warning and not run: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#With variable set as an integer and evaluating to true/false
#*** These statements will not evaluate properly: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" == true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then
#With variable set as an true/false builtin and evaluating to true/false
#*** These statements will not evaluate properly: *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = 0 ]; then
#
if [[ "${The_world_is_flat}" = 0 ]]; then
#
if [ "${The_world_is_flat}" == 0 ]; then
#
if [[ "${The_world_is_flat}" == 0 ]]; then
所以,现在到底有效。使用true / false内置函数进行比较和评估(正如Mike Hunt指出的那样,不要将它们括在引号中)。然后使用单或双等号(=或==)和单括号或双括号([]或[[]])。就个人而言,我喜欢双等号,因为它让我想起其他编程语言的逻辑比较,而双引号只是因为我喜欢打字。所以这些工作:
#With variable set as an integer and evaluating to true/false
#*** These statements will work properly: *****
#
The_world_is_flat=true/false;
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then
你有它。
答案 10 :(得分:3)
我想念这里的关键点,即便携性。这就是为什么我的标题本身就有POSIX。
基本上,所有投票的答案都是正确的,除了它们BASH - 具体太多了。
基本上,我只想添加有关可移植性的更多信息。
[
和]
中的[ "${var}" = true ]
括号不是必需的,您可以省略它们并直接使用test
命令:
test "${var}" = true && CodeIfTrue || CodeIfFalse
请注意,我不再推荐此,因为它已被慢慢弃用。
想象一下这些单词true
和false
对shell的意义,自己测试一下:
echo $(( true ))
0
echo $(( false ))
1
但是使用引号:
echo $(( "true" ))
bash: "true": syntax error: operand expected (error token is ""true"") sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""
同样适用:
echo $(( "false" ))
除了字符串外,shell不能解释它。我希望您能够了解使用正确的关键字没有引号有多好。
但在之前的答案中没有人说过。
这是什么意思?好吧,好几件事。
您应该习惯布尔关键字实际上被视为数字,即true
= 0
和false
= 1
,请记住所有非零值被视为false
。
由于它们被视为数字,你应该像对待它们一样,即如果你定义变量说:
var_bool=true
echo "${var_bool}"
true
您可以使用以下方法创建相反的值:
var_bool=$(( 1 - ${var_bool} ))
echo "${var_bool}"
1
正如您自己所看到的,shell首次使用时会打印true
字符串,但从那时起,它全部通过代表0
的数字true
或{ {1}}分别代表1
。
首先,一个好习惯是分配false
而不是0
; true
代替1
。
第二个好习惯是测试变量是否等于零:
false
答案 11 :(得分:2)
在许多编程语言中,布尔类型是整数或被实现为整数的子类型,其中true
的行为类似于1
,而false
的行为类似于0
:
Mathematically,布尔代数类似于2的整数算术运算。因此,如果语言不提供本机布尔类型,则最自然和有效的解决方案是使用整数。这几乎适用于任何语言。例如,在Bash中,您可以执行以下操作:
# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false
(((表达式))
根据以下算术评估中所述的规则评估表达式。如果表达式的值不为零,则返回状态为0;否则,返回值为0。否则返回状态为1。这完全等同于let“表达式”。
答案 12 :(得分:1)
这是一个简短的if true
的实现。
# Function to test if a variable is set to "true"
_if () {
[ "${1}" == "true" ] && return 0
[ "${1}" == "True" ] && return 0
[ "${1}" == "Yes" ] && return 0
return 1
}
示例1
my_boolean=true
_if ${my_boolean} && {
echo "True Is True"
} || {
echo "False Is False"
}
示例2
my_boolean=false
! _if ${my_boolean} && echo "Not True is True"
答案 13 :(得分:1)
另一种使用布尔值的方法是测试值的空性。这样做的好处是可以缩短测试时间:
first=1 # A true value
second= # A false value
[ -n "$first" ] && echo 'First var is true'
[ -z "$first" ] && echo 'First var is false'
[ -n "$second" ] && echo 'Second var is true'
[ -z "$second" ] && echo 'Second var is false'
输出:
First var is true
Second var is false
这里是使用 bash 的替代测试语法:[[ -n $one ]]
答案 14 :(得分:1)
这是一个适合我的简单示例:
temp1=true
temp2=false
if [ "$temp1" = true ] || [ "$temp2" = true ]
then
echo "Do something."
else
echo "Do something else."
fi
答案 15 :(得分:1)
以下是对miku original answer的改进,解决了Dennis Williamson对案例的担忧,其中未设置变量:
the_world_is_flat=true
if ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
并测试变量是否为false
:
if ! ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
关于变量中含有令人讨厌的内容的其他情况,这是任何输入程序的外部输入的问题。
在信任之前,必须验证任何外部输入。但是,当收到该输入时,该验证必须只进行一次。
通过像Dennis Williamson所建议的变量的每次使用,它都不会影响程序的性能。
答案 16 :(得分:1)
我发现现有的答案令人困惑。
就个人而言,我只想拥有像C一样的外观和作品。
此代码段每天在制作中多次使用:
snapshotEvents=true
if ($snapshotEvents)
then
# do stuff if true
fi
为了让每个人都开心,我测试了一下:
snapshotEvents=false
if !($snapshotEvents)
then
# do stuff if false
fi
这也很好。
$snapshotEvents
评估变量值的内容。所以你需要$
。
你真的不需要括号,我发现它们很有帮助。
测试:GNU Bash,版本4.1.11(2) - 发布
Bash Guide for Beginners,Machtelt Garrels,v1.11,2008
答案 17 :(得分:0)
我的发现和建议与其他帖子有所不同。我发现我可以像在任何“常规”语言中一样使用true / false,而无需建议“跳跳” ...不需要[]或显式字符串比较...我尝试了多个Linux发行版,我进行了测试bash,破折号和busybox。我跑来跑去,没有她砰的一声……结果总是一样的。我不确定最初被投票最多的帖子在谈论什么。也许时代已经改变,仅此而已?
如果将变量设置为true
,则在条件条件下其结果为true。将其设置为false
,其结果为false。非常简单!唯一需要注意的是,未定义变量的求值结果也为 true !如果这样做相反,那会很好,但这就是诀窍-您只需要将布尔值显式设置为true或false 。
请参见下面的示例bash和结果。如果要确认...,请自己进行测试...
#!/bin/sh
#not yet defined...
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;
myBool=true
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;
myBool=false
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;
收益
when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false
答案 18 :(得分:0)
您可以使用GFlags:https://gflags.github.io/gflags/
它为您提供了定义的选项:DEFINE_bool
示例:
DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
在命令行中,您可以定义:
sh script.sh --bigmenu
sh script.sh --nobigmenu # False
答案 19 :(得分:0)
这是一项速度测试,涉及在Bash中测试“布尔”值的不同方法:
#!/bin/bash
rounds=100000
b=true # for true; b=false for false
type -a true
time for i in $(seq $rounds); do command $b; done
time for i in $(seq $rounds); do $b; done
time for i in $(seq $rounds); do [ "$b" == true ]; done
time for i in $(seq $rounds); do test "$b" == true; done
time for i in $(seq $rounds); do [[ $b == true ]]; done
b=x; # or any non-null string for true; b='' for false
time for i in $(seq $rounds); do [ "$b" ]; done
time for i in $(seq $rounds); do [[ $b ]]; done
b=1 # or any non-zero integer for true; b=0 for false
time for i in $(seq $rounds); do ((b)); done
它会打印类似的东西
true is a shell builtin
true is /bin/true
real 0m0,815s
user 0m0,767s
sys 0m0,029s
real 0m0,562s
user 0m0,509s
sys 0m0,022s
real 0m0,829s
user 0m0,782s
sys 0m0,008s
real 0m0,782s
user 0m0,730s
sys 0m0,015s
real 0m0,402s
user 0m0,391s
sys 0m0,006s
real 0m0,668s
user 0m0,633s
sys 0m0,008s
real 0m0,344s
user 0m0,311s
sys 0m0,016s
real 0m0,367s
user 0m0,347s
sys 0m0,017s
答案 20 :(得分:0)
关于语法,这是我使用的一种简单方法(通过示例)来一致且明智地管理布尔逻辑:
# tests
var=
var=''
var=""
var=0
var=1
var="abc"
var=abc
if [[ -n "${var}" ]] ; then
echo 'true'
fi
if [[ -z "${var}" ]] ; then
echo 'false'
fi
# results
# var= # false
# var='' # false
# var="" # false
# var=0 # true
# var=1 # true
# var="abc" # true
# var=abc # true
如果从未声明该变量,则答案为:# false
因此,使用此语法方法将变量设置为true的简单方法是var=1
;相反,var=''
。
参考:
-n
=如果var字符串的长度不为零,则为true。
-z
=如果var字符串的长度为零,则为true。
答案 21 :(得分:-2)
Bash确实会将此问题与[
,[[
,((
,$((
等问题混淆。
所有对待彼此的代码空间。我想这主要是历史性的,Bash不得不偶尔假装sh
。
大多数时候,我可以选择一种方法并坚持下去。在这个例子中,我倾向于声明(最好在一个公共的库文件中,我可以在我的实际脚本中包含.
)。
TRUE=1; FALSE=0
然后,我可以使用((
... ))
算术运算符进行测试。
testvar=$FALSE
if [[ -d ${does_directory_exist} ]]
then
testvar=$TRUE;
fi
if (( testvar == TRUE )); then
# do stuff because the directory does exist
fi
你必须受到纪律处分。您的testvar
必须始终设置为$TRUE
或$FALSE
。
在((
... ))
比较器中,您不需要前面的$
,这使其更具可读性。
我可以使用((
... ))
,因为$TRUE=1
和$FALSE=0
,即数字值。
缺点是偶尔使用$
:
testvar=$TRUE
这不是那么漂亮。
这不是一个完美的解决方案,但它涵盖了所有情况,我需要进行这样的测试。
答案 22 :(得分:-2)
替代-使用功能
is_ok(){ :;}
is_ok(){ return 1;}
is_ok && echo "It's OK" || echo "Something's wrong"
对该函数的定义不太直观,但是检查其返回值非常容易。