我知道在shell中感叹号可以反转条件的结果。这里我想用它来测试变量是真还是假。
#! /bin/bash bat=false if [ ! $bar ]; then echo 'bar is false' else echo 'bar is true' fi
我以为是“酒吧是假的”。但结果却恰恰相反。然后使用“$bar”==“false”。这是正确的。那么使用感叹号的技巧是什么呢?当我们对文件进行测试时,它只会反转结果吗?
uqxowvwt1#
tl;dr[ ! $bar ]将$bar视为 * 字符串 , 任何非空 * 字符串都被认为是“true”-包括文字false;换句话说:[ ! 'true' ] && [ ! 'false' ]both 的结果都是“false”,因为这两种情况下的操作数都是非空字符串,而!会对结果取反。
[ ! $bar ]
$bar
false
[ ! 'true' ]
[ ! 'false' ]
!
因此,必须使用 string 比较:
bar=false if [ ! "$bar" = 'true' ]; then # same as: [ "$bar" != 'true' ] echo 'bar is false' else echo 'bar is true' fi
在Bash中,也可以使用[[ ! $bar == 'true' ]]或[[ $bar != 'true' ]];除非你需要保持POSIX兼容性,I suggest using [[ ... ]]。在[ ... ]和[[ ... ]](特定于Bash)的上下文中,变量值默认为 * 字符串,并且,通常,POSIX类shell * 没有显式的布尔数据类型 *。一元运算符!将其操作数 * 隐式地 * 解释为布尔值,布尔上下文中的 * 字符串 * 解释如下:
[[ ! $bar == 'true' ]]
[[ $bar != 'true' ]]
[[ ... ]]
[ ... ]
1
0
因此,! $bar的计算结果为“false”,因为$bar(包含非空字符串'false')的计算结果为“true”,而!将其反转。!也可以在条件之外直接否定命令的成功状态(包括[)。由于false和true也以 * 命令名 * 的形式存在(通常是作为shell内置程序),因此您可以 * 执行以下操作,但请注意,它仅适用于字面量为false或true的变量值:
! $bar
'false'
[
true
bar=false if ! "$bar"; then echo 'bar is false' else echo 'bar is true' fi
类POSIX shell只有两种基本的(标量)数据类型:
=
==
<
<=
>
>=
-eq
lt
le
gt
ge
$(( ... ))
在Bash中,您还可以使用(( ... ))作为算术 * 条件 *。注意:根据POSIX,你不能 type 一个变量作为一个整数(因为没有办法 * 声明 * 一个shell变量),所以它只在使用算术运算符的比较中/在算术上下文中隐式地 * 被视为一个 *。然而,在Bash中,你可以用declare -i/local -i * 声明 * 整型变量,但是在条件/算术上下文中,仍然是操作符/算术上下文的选择决定了值是被当作字符串还是整数。shell中的布尔值被 * 隐式地 * 表示为 * 退出代码 *,这是通常的布尔到整数Map的 * 反转 *:
(( ... ))
declare -i
local -i
vi4fp9gy2#
有关[或test实用程序的可移植使用的详细信息,请参阅test的POSIX规范。如果你使用[ ! $bar ],你是在玩火。
test
你应该正常地写[ ! "$bar" ],如果$bar为空,它将正常工作。您可以(可以说应该)使用显式测试:
[ ! "$bar" ]
[ -z "$bar" ]
[ -n "$bar" ]
但为了避免混淆,引号是必须的n on-empty和z ero-length是助记词。
n
z
$ 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
它将(可能)帮助你了解发生了什么。不过,输出相当冗长。
lstz6jyr3#
if测试命令的结果,不能直接测试变量的值。在本例中,您将它与test/[命令结合使用,后者是一个普通命令,可以在任何地方使用。
if
[ -f ./foo.txt ] && echo "foo.txt exists"
或等效地
test -f ./foo.txt && echo "foo.txt exists"
两者都测试在路径./foo.txt处是否存在文件。根据你所说的“true”的含义,你可以使用test或[ shell内置来确定一个变量是否等于另一个变量,以及其他一些功能,比如测试一个目录或文件是否存在。可以使用if [ -z "$variable" ]; then ...; fi来检查变量是否为空字符串。如果你想检查变量是否被设置,甚至是空值,你可以使用参数扩展[ -z "${var+x}" ]。只有当var未定义时,它才计算为true(意味着退出状态为零)。如果你想将一个变量与一个固定的字符串进行比较,你可以使用[ "$var" = "some-string" ]或case。
./foo.txt
if [ -z "$variable" ]; then ...; fi
[ -z "${var+x}" ]
var
[ "$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
意思是一样的
3条答案
按热度按时间uqxowvwt1#
tl;dr
[ ! $bar ]
将$bar
视为 * 字符串 , 任何非空 * 字符串都被认为是“true”-包括文字false
;换句话说:[ ! 'true' ]
&&[ ! 'false' ]
both 的结果都是“false”,因为这两种情况下的操作数都是非空字符串,而!
会对结果取反。因此,必须使用 string 比较:
在Bash中,也可以使用
[[ ! $bar == 'true' ]]
或[[ $bar != 'true' ]]
;除非你需要保持POSIX兼容性,I suggest using[[ ... ]]
。在
[ ... ]
和[[ ... ]]
(特定于Bash)的上下文中,变量值默认为 * 字符串,并且,通常,POSIX类shell * 没有显式的布尔数据类型 *。一元运算符
!
将其操作数 * 隐式地 * 解释为布尔值,布尔上下文中的 * 字符串 * 解释如下:1
(!))false
--都被认为是**“true”**(退出代码0
(!))因此,
! $bar
的计算结果为“false”,因为$bar
(包含非空字符串'false'
)的计算结果为“true”,而!
将其反转。!
也可以在条件之外直接否定命令的成功状态(包括[
)。由于
false
和true
也以 * 命令名 * 的形式存在(通常是作为shell内置程序),因此您可以 * 执行以下操作,但请注意,它仅适用于字面量为false
或true
的变量值:背景信息
类POSIX shell只有两种基本的(标量)数据类型:
[ ... ]
和[[ ... ]]
条件中,运算符=
(Bash中的==
),<
,<=
,>
,>=
执行 * 字符串 * 比较。[ ... ]
和[[ ... ]]
条件中,必须使用不同的 * 算术 * 运算符(-eq
、lt
、le
、gt
、ge
)来执行 * 数值 * 比较$(( ... ))
)中,==
,<
,<=
,>
,>=
具有其通常的 * 数字 * 含义。在Bash中,您还可以使用
(( ... ))
作为算术 * 条件 *。注意:根据POSIX,你不能 type 一个变量作为一个整数(因为没有办法 * 声明 * 一个shell变量),所以它只在使用算术运算符的比较中/在算术上下文中隐式地 * 被视为一个 *。
然而,在Bash中,你可以用
declare -i
/local -i
* 声明 * 整型变量,但是在条件/算术上下文中,仍然是操作符/算术上下文的选择决定了值是被当作字符串还是整数。shell中的布尔值被 * 隐式地 * 表示为 * 退出代码 *,这是通常的布尔到整数Map的 * 反转 *:
0
(!)1
(!)或任何其他 * 非零 * 退出代码。vi4fp9gy2#
有关
[
或test
实用程序的可移植使用的详细信息,请参阅test
的POSIX规范。如果你使用
[ ! $bar ]
,你是在玩火。$bar
是一个空字符串,它退化为一个参数形式的test,该参数为!
,并成功退出,因为!
不是一个空字符串。$bar
不是空字符串,则参数为!
和$bar
的值,这将确定非空字符串是非空的,然后反转条件,因此它以失败状态退出。你应该正常地写
[ ! "$bar" ]
,如果$bar
为空,它将正常工作。您可以(可以说应该)使用显式测试:[ -z "$bar" ]
用于测试空(零长度)字符串,以及[ -n "$bar" ]
测试非空字符串但为了避免混淆,引号是必须的
n
on-empty和z
ero-length是助记词。有些人更喜欢Bash(Korn shell,.)操作符
[[
,它的行为不同。您可以尝试使用此代码主题的变体:它将(可能)帮助你了解发生了什么。不过,输出相当冗长。
lstz6jyr3#
if
测试命令的结果,不能直接测试变量的值。在本例中,您将它与test
/[
命令结合使用,后者是一个普通命令,可以在任何地方使用。或等效地
两者都测试在路径
./foo.txt
处是否存在文件。根据你所说的“true”的含义,你可以使用
test
或[
shell内置来确定一个变量是否等于另一个变量,以及其他一些功能,比如测试一个目录或文件是否存在。可以使用
if [ -z "$variable" ]; then ...; fi
来检查变量是否为空字符串。如果你想检查变量是否被设置,甚至是空值,你可以使用参数扩展
[ -z "${var+x}" ]
。只有当var
未定义时,它才计算为true
(意味着退出状态为零)。如果你想将一个变量与一个固定的字符串进行比较,你可以使用
[ "$var" = "some-string" ]
或case
。请注意,您可以使用
!
否定test
/[
的结果。否定了这个条件。
但是,
!
也可以作为test
/[
的参数意思是一样的