has*_*anm 884 bash shell scripting boolean sh
我尝试使用以下语法在shell脚本中声明一个布尔变量:
variable=$false
variable=$true
Run Code Online (Sandbox Code Playgroud)
它是否正确?另外,如果我想更新该变量,我会使用相同的语法吗?最后,使用布尔变量作为正确的表达式是以下语法:
if [ $variable ]
if [ !$variable ]
Run Code Online (Sandbox Code Playgroud)
mik*_*iku 1101
修订回答(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
Run Code Online (Sandbox Code Playgroud)
原始答案
警告: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
Run Code Online (Sandbox Code Playgroud)
From:在Bash中使用布尔变量
这里包含原始答案的原因是因为2014年2月12日修订前的评论仅适用于原始答案,并且许多评论在与修订后的答案相关时是错误的.例如,Dennis Williamson关于true
2010年6月2日内置bash的评论仅适用于原始答案,而非修订版.
Den*_*nis 733
bool=true
if [ "$bool" = true ]
Run Code Online (Sandbox Code Playgroud)
我不推荐接受的答案1.它的语法很漂亮,但它有一些缺陷.
假设我们有以下条件.
if $var; then
echo 'Muahahaha!'
fi
Run Code Online (Sandbox Code Playgroud)
在以下情况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
Run Code Online (Sandbox Code Playgroud)
通常,只有当"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!
Run Code Online (Sandbox Code Playgroud)
引用变量更安全,例如if "$var"; then
.在上述情况下,您应该收到一条警告,指出找不到该命令.但我们仍然可以做得更好(请参阅我在底部的建议).
这种方法也有意想不到的行为.
var=false
if [ $var ]; then
echo "This won't print, var is false!"
fi
# Outputs:
# This won't print, var is false!
Run Code Online (Sandbox Code Playgroud)
您可能希望上述条件计算为false,因此从不执行嵌套语句.惊喜!
引用value("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
Run Code Online (Sandbox Code Playgroud)
它们几乎都是等价的.你需要输入比其他答案中的方法更多的键击5但你的代码将更具防御性.
man woman
即使没有这样的手册页,Eg 仍将被视为有效命令.Mik*_*olt 163
这里似乎存在一些关于Bash内置的误解true
,更具体地说,关于Bash如何扩展和解释括号内的表达式.
miku的答案中的代码与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
Run Code Online (Sandbox Code Playgroud)
这里唯一的区别是被比较的四个字符是'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
Run Code Online (Sandbox Code Playgroud)
两个代码片段的行为方式都相同,但括号完全改变了引擎盖下的内容.
这是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
Run Code Online (Sandbox Code Playgroud)
这段代码只打印"Nice try".不会调用reboot命令.
var=reboot
if [ $var ]; then
echo 'Nice try.'
fi
Run Code Online (Sandbox Code Playgroud)
更新(2014-04-14)要回答有关=
和==
:AFAIK 之间差异的评论中的问题,没有区别.该==
运营商特定的Bash-代名词=
,而据我所看到的,他们的工作完全一样在所有上下文中.
但是请注意,是我专门谈论=
和==
在任一使用的字符串比较操作[ ]
或[[ ]]
测试.我并不是暗示=
和==
互换无处不在bash.
例如,你显然无法进行变量赋值==
,例如var=="foo"
(从技术上讲你可以做到这一点,但是值var
将是"=foo"
,因为Bash没有在==
这里看到一个运算符,它看到一个=
(赋值)运算符,然后是字面值="foo"
,刚刚成为"=foo"
).
此外,虽然=
和==
可以互换,你应该记住,如何将这些测试工作也取决于您是否使用它里面[ ]
或[[ ]]
,还取决于是否操作数被引用.你可以阅读更多关于高级Bash脚本编程指南:7.3其他比较操作符(向下滚动到的讨论=
和==
).
Quo*_*ons 49
使用算术表达式.
#!/bin/bash
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
Run Code Online (Sandbox Code Playgroud)
输出:
真的
不是假的
Hub*_*iak 29
长话短说:
bash所具有的是比较和条件方面的布尔表达式.也就是说,你可以在bash中声明和比较的是字符串和数字.而已.
无论你在哪里看到true
或false
在bash中,它都是一个字符串或一个命令/ builtin,它只用于退出代码.
这个语法......
if true; then ...
Run Code Online (Sandbox Code Playgroud)
基本上......
if COMMAND; then ...
Run Code Online (Sandbox Code Playgroud)
只要命令返回退出代码0 true
,条件就为真.它false
是Bash内置的,有时也是独立的程序,除了返回相应的退出代码之外什么都不做.
上述条件相当于:
COMMAND && ...
Run Code Online (Sandbox Code Playgroud)
使用方括号或test
命令时,您依赖于该构造的退出代码.请记住,[ ]
并且[[ ]]
也只有命令/建宏像任何其他.所以......
if [[ 1 == 1 ]]; then echo yes; fi
Run Code Online (Sandbox Code Playgroud)
对应于
if COMMAND; then echo yes; fi
Run Code Online (Sandbox Code Playgroud)
而COMMAND
这里是[[ 1 == 1 ]]
该if..then..fi
结构只是语法糖.您始终只需运行由双符号分隔的命令即可获得相同的效果:
[[ 1 == 1 ]] && echo yes
Run Code Online (Sandbox Code Playgroud)
在使用true
和false
在这些测试结构中,您实际上只传递字符串"true"
或"false"
测试命令.这是一个例子:
信不信由你,但这些条件都产生了同样的结果:
if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...
Run Code Online (Sandbox Code Playgroud)
为了使未来的读者清楚,我建议总是使用引号true
和false
:
if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...
Run Code Online (Sandbox Code Playgroud)
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 `==`
Run Code Online (Sandbox Code Playgroud)
if [[ "${var}" != "true" ]]; then ... # Creates impression of Booleans. It can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".
Run Code Online (Sandbox Code Playgroud)
小智 16
很久以前,当我们所拥有的一切都是sh
,通过依赖test
程序约定处理的布尔值,test
如果没有参数运行则返回错误的退出状态.这允许人们将未设置的变量视为false,将变量设置为任何值为true.今天,测试内置于test
并且通常以其一个字符别名[
(或者在缺少它的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
Run Code Online (Sandbox Code Playgroud)
由于报价的约定,脚本编写者喜欢使用复合命令[[
,模仿test
,但有更好的语法:用空格变量不需要被引用,可以使用&&
和||
怪异优先逻辑运算符,并有对数量没有POSIX限制条款.
例如,要确定是否设置了FLAG并且COUNT是大于1的数字:
FLAG="u p"
COUNT=3
if [[ $FLAG && $COUNT -gt '1' ]] ; then
echo 'Flag up, count bigger than 1'
else
echo 'Nope'
fi
Run Code Online (Sandbox Code Playgroud)
当需要空格,零长度字符串和空变量以及脚本需要使用多个shell时,这些东西会让人感到困惑.
sjs*_*sam 11
如何在shell脚本中声明和使用布尔变量?
与许多其他编程语言不同,Bash不会通过"类型"来隔离其变量.[1]
所以答案很清楚.Boolean variable
bash中没有.但是:
使用declare语句,我们可以将值赋值限制为变量.[2]
#!/bin/bash
declare -ir BOOL=(0 1) # Remember BOOL can't be unset till this shell terminates
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"
Run Code Online (Sandbox Code Playgroud)
该r
选件declare
和readonly
使用,明确规定了变量是只读的.希望目的很明确.
Pyr*_*cal 10
为什么不使用比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
Run Code Online (Sandbox Code Playgroud)
Buv*_*inJ 10
我的发现和建议与其他帖子略有不同。我发现我基本上可以像使用任何“常规”语言一样使用“布尔值”,而没有建议的“跳圈”……
不需要[]
或明确的字符串比较......我尝试了多个 Linux 发行版。我测试了 Bash、Dash 和BusyBox。结果总是一样的。我不确定最初的最高投票帖子在谈论什么。也许时代变了,这就是它的全部?
如果将变量设置为true
,则它随后在条件中评估为“肯定”。将其设置为false
,它的计算结果为“负数”。很直接!唯一需要注意的是,未定义的变量的计算结果也像true!如果它做相反的事情会很好(就像在大多数语言中一样),但这就是诀窍 -你只需要明确地将你的布尔值初始化为 true 或 false。
为什么它以这种方式工作?这个答案是双重的。A)shell 中的真/假真的意味着“没有错误”与“错误”(即 0 与其他任何东西)。B) true/false 不是值 - 而是shell 脚本中的语句!关于第二点,单独执行true
或false
在一行上将您所在块的返回值设置为该值,即false
“遇到错误”的声明,其中 true 会“清除”该值。将它与对变量的赋值一起使用“返回”到变量中。一个未定义的变量计算像true
在条件,因为同样表示0或“没有遇到错误”。
请参阅下面的示例 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;
Run Code Online (Sandbox Code Playgroud)
产量
when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false
Run Code Online (Sandbox Code Playgroud)
在许多编程语言,布尔类型是或作为实现,整数,其中的亚型true
表现得像1
和false
行为就像0
:
在数学上,布尔代数类似于整数算术模 2。因此,如果一种语言不提供原生布尔类型,最自然和有效的解决方案是使用整数。这适用于几乎任何语言。例如,在 Bash 中,您可以执行以下操作:
# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false
Run Code Online (Sandbox Code Playgroud)
((表达))
表达式根据以下算术求值中描述的规则进行求值。如果表达式的值非零,则返回状态为 0;否则返回状态为 1。这完全等同于 let "expression"。
我在这里想念关键点,那就是可移植性。这就是为什么我的标头本身具有POSIX的原因。
本质上,所有投票的答案都是正确的,除了它们都是特定于Bash的。
基本上,我只希望添加有关可移植性的更多信息。
[
和]
in之[ "${var}" = true ]
类的括号不是必需的,您可以忽略它们并test
直接使用命令:
test "${var}" = true && CodeIfTrue || CodeIfFalse
Run Code Online (Sandbox Code Playgroud)请注意,由于它已逐渐被弃用,因此我不再建议这样做。
想象一下那些话true
,并false
指到外壳,测试自己:
echo $(( true ))
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)0
echo $(( false ))
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)1
但是使用引号:
echo $(( "true" ))
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)bash: "true": syntax error: operand expected (error token is ""true"") sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""
同样适用于:
echo $(( "false" ))
Run Code Online (Sandbox Code Playgroud)
除了字符串,shell无法解释它。希望您能想到使用不带引号的适当关键字的效果如何。
但是没有人在先前的回答中说过。
这是什么意思?好吧,几件事。
您应该习惯了Boolean关键字实际上被当作数字对待,即true
= 0
和false
= 1
,请记住,所有非零值都被视为false
。
由于它们被当作数字对待,因此您也应该像对待数字一样对待它们,即,如果定义变量,请说:
var_bool=true
echo "${var_bool}"
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)true
您可以使用以下方法创建相反的值:
var_bool=$(( 1 - ${var_bool} ))
echo "${var_bool}"
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)1
如您所见,shell true
第一次使用时会打印字符串,但是从那时起,它都分别通过数字0
表示true
或1
表示来false
工作。
首先,一个好的习惯是分配0
而不是true
;1
代替false
。
第二个好习惯是测试变量是否为/不等于零:
if [ "${var_bool}" -eq 0 ]; then YourCodeIfTrue; else YourCodeIfFalse; fi
Run Code Online (Sandbox Code Playgroud)关于语法,这是一种简单的方法,我使用它(通过示例)来一致而理智地管理布尔逻辑:
# 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
Run Code Online (Sandbox Code Playgroud)
如果从未声明变量,则答案是: # false
所以,一个简单的方法给一个变量设置为true(使用此语法的方法)将是var=1
; 反之,var=''
。
参考:
-n
= 如果 var 字符串的长度非零,则为真。
-z
= 如果 var 字符串的长度为零,则为真。
小智 5
Bill Parker被否决了,因为他的定义与常规代码约定相反。通常,将true定义为0,将false定义为非零。1代表false,9999和-1代表false。与函数返回值相同-0表示成功,非零表示失败。抱歉,我还没有投票或直接回复他的信誉。
Bash建议现在使用双括号代替单括号,这是一种习惯,麦克·霍尔特(Mike Holt)给出的链接说明了它们在工作方式上的差异。7.3。其他比较运算符
一方面,-eq
是一个数值运算符,所以有了代码
#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
Run Code Online (Sandbox Code Playgroud)
将发出错误语句,期望使用整数表达式。这适用于任何一个参数,因为两者都不是整数值。但是,如果在它周围加上双括号,它将不会发出错误声明,但是会产生错误的值(可能是50%的可能排列)。它将评估为[[0 -eq真]] =成功,但也评估为[[0 -eq真]] =成功,这是错误的(hmmm ....该内建值是什么?)。
#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
Run Code Online (Sandbox Code Playgroud)
条件的其他排列也会产生错误的输出。基本上,任何将变量设置为数值并将其与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
Run Code Online (Sandbox Code Playgroud)
所以,现在要做什么。对比较和评估都使用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
Run Code Online (Sandbox Code Playgroud)
你有它。
使用布尔值的另一种方法是测试值的空性。这样做的优点是可以缩短测试时间:
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'
Run Code Online (Sandbox Code Playgroud)
输出:
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'
Run Code Online (Sandbox Code Playgroud)
这是 bash 的替代测试语法:[[ -n $one ]]
归档时间: |
|
查看次数: |
841820 次 |
最近记录: |