我知道在shell中,感叹号可以反转条件的结果。这里我想使用它来测试变量是真还是假。
#! /bin/bash
bat=false
if [ ! $bar ]; then
echo 'bar is false'
else
echo 'bar is true'
fi
我原本期望的是'bar is false',但结果却相反了。然后我使用"$bar" == "false",这是正确的。
那么感叹号的使用技巧是什么?它只能在测试文件时才能翻转结果吗?
我知道在shell中,感叹号可以反转条件的结果。这里我想使用它来测试变量是真还是假。
#! /bin/bash
bat=false
if [ ! $bar ]; then
echo 'bar is false'
else
echo 'bar is true'
fi
我原本期望的是'bar is false',但结果却相反了。然后我使用"$bar" == "false",这是正确的。
那么感叹号的使用技巧是什么?它只能在测试文件时才能翻转结果吗?
tl;dr
[ ! $bar ]
将$bar
视为字符串,而任何非空字符串都被视为"true" - 包括字面上的false
;换句话说:[ ! 'true' ]
和[ ! 'false' ]
都评估为"false",因为在这两种情况下,操作数都是非空字符串,而!
对结果进行否定。
因此,您必须使用字符串比较:
bar=false
if [ ! "$bar" = 'true' ]; then # same as: [ "$bar" != 'true' ]
echo 'bar is false'
else
echo 'bar is true'
fi
[[ ! $bar == 'true' ]]
或[[ $bar != 'true' ]]
;除非你需要保持POSIX兼容性,我建议使用[[ ... ]]
。
[ ... ]
和[[ ... ]]
(特定于Bash)的上下文中,默认情况下变量值是字符串,而且通常类似POSIX的shell没有显式的布尔数据类型。!
将其操作数隐式解释为布尔值,在布尔上下文中,字符串被解释如下:
1
(!))false
- 被认为是"true"(退出码0
(!))! $bar
计算结果为"false",因为$bar
- 包含非空字符串'false'
- 计算结果为"true",而!
将其取反。
!
也可以在条件语句之外直接用来否定命令的执行结果(包括[
)。
由于false
和true
也作为命令名称存在(通常作为shell内置命令),你可以按照以下方式操作,但请注意,这只适用于变量值为字面值false
或true
的情况:
bar=false
if ! "$bar"; then
echo 'bar is false'
else
echo 'bar is true'
fi
类似POSIX的shell只有两种基本(标量)数据类型:
字符串(默认情况下):
[ ... ]
和 [[ ... ]]
中,运算符 =
(在 Bash 中为 ==
)、<
、<=
、>
、>=
用于进行字符串比较。整数:
[ ... ]
和 [[ ... ]]
中,必须使用不同的算术运算符(-eq
、lt
、le
、gt
、ge
)进行数值比较。$(( ... ))
)中,==
、<
、<=
、>
、>=
具有它们通常的数值意义。(( ... ))
作为算术条件语句。test
的详细内容,了解[
或test
实用程序的可移植使用方法。[ ! $bar ]
,那么您就很危险。
如果$bar
是空字符串,则它会退化为测试的单参数形式,该参数为!
,并成功退出,因为!
不是空字符串。
如果$bar
不是空字符串,则参数是!
和$bar
的值,这将建立非空字符串是非空的事实,然后反转条件,因此以失败状态退出。
[ ! "$bar" ]
,这样即使$bar
为空也能正确工作。您可以(有人可能会认为应该)使用显式测试:
[ -z "$bar" ]
以测试空(零长度)字符串,以及[ -n "$bar" ]
以测试非空字符串$ bar=
$ [ ! $bar ] || echo Test failed
$ bar=xyz
$ [ ! $bar ] || echo Test failed
Test failed
$ [ ! "$bar" ] || echo Test failed
Test failed
$ bar=
$ [ ! "$bar" ] || echo Test failed
$ [ -n "$bar" ] || echo Test failed
Test failed
$ [ -z "$bar" ] || echo Test failed
$
有些人更喜欢使用Bash(Korn shell,...)运算符[[
,其行为不同。您可以尝试对此代码主题进行变化:
set -x
bar=
[ ! $bar ] || echo Test failed
bar=xyz
[ ! $bar ] || echo Test failed
[ ! "$bar" ] || echo Test failed
bar=
[ ! "$bar" ] || echo Test failed
[ -n "$bar" ] || echo Test failed
[ -z "$bar" ] || echo Test failed
bar=xyz
[ -n "$bar" ] || echo Test failed
[ -z "$bar" ] || echo Test failed
bar=
[[ ! $bar ]] || echo Test failed
bar=xyz
[[ ! $bar ]] || echo Test failed
[[ ! "$bar" ]] || echo Test failed
bar=
[[ ! "$bar" ]] || echo Test failed
[[ -n "$bar" ]] || echo Test failed
[[ -z "$bar" ]] || echo Test failed
bar=xyz
[[ -n "$bar" ]] || echo Test failed
[[ -z "$bar" ]] || echo Test failed
bar=
[[ -n $bar ]] || echo Test failed
[[ -z $bar ]] || echo Test failed
bar=xyz
[[ -n $bar ]] || echo Test failed
[[ -z $bar ]] || echo Test failed
set +x # Unnecessary if you save this in a script file and don't dot (source) it
它(可能)会帮助你理解发生了什么。但输出内容相当冗长。
if
语句用于测试命令的结果,不能直接测试变量的值。在这种情况下,您需要与 test
/[
命令一起使用,这是一个普通的命令,可以在任何地方使用。
[ -f ./foo.txt ] && echo "foo.txt exists"
test -f ./foo.txt && echo "foo.txt exists"
两种方法都可以测试路径./foo.txt
下的文件是否存在。
根据你所说的“真实”,你可以使用test
或[
shell内置命令来确定变量是否等于另一个变量,以及用于测试目录或文件是否存在等其他功能。
您可以使用if [ -z "$variable" ]; then ...; fi
来检查变量是否为空字符串。
如果您想检查变量是否被设置为任何值,甚至是空值,您可以使用参数扩展[ -z "${var+x}" ]
。只有在var
未定义时,它才评估为true
(意味着具有退出状态零)。
如果您想将变量与固定字符串进行比较,则可以使用[ "$var" = "some-string" ]
或使用case
。
case "$var" in
some-string)
dostuff
;;
esac
!
对 test
/[
的结果进行否定。if ! [ -z "$var" ]; then
do-something
fi
对条件取反。
但是,在test
/[
中,!
也可以作为参数使用。
if [ ! -z "$var" ]; then
do-something
fi
意思是相同的。
[ … ]
/ [[ … ]]
中或作为 test
操作数时,!
是完全有效的。您只需要了解它的操作数如何被评估:
$bar
不是按您期望的方式进行评估的:它是一个 _字符串_,并且由于它是一个 非空 字符串 - 无论其 内容 如何 - 它被认为是“true”。 - mklement0!
是test
命令的一个有效参数。当且仅当"$somestring"
扩展为非空字符串时,test "$somestring"
将退出0。test ! "$something"
则相反。话虽如此,通常更典型的是使用test -z "$something"
或test -n "$something"
来测试是否为空,因为这可以处理$something
是像-z
这样的奇怪值的边缘情况。 - Greg Nisbet
true
和false
都只是字符串,与kitten
这样的任何其他单词本质上没有区别。 - that other guy