bash shell中测试变量是否为真的感叹号

5t7ly7z5  于 2023-10-23  发布在  Shell
关注(0)|答案(3)|浏览(155)

我知道在shell中感叹号可以反转条件的结果。这里我想用它来测试变量是真还是假。

#! /bin/bash
bat=false
if [ ! $bar ]; then
    echo 'bar is false'
else
   echo 'bar is true'
fi

我以为是“酒吧是假的”。但结果却恰恰相反。然后使用“$bar”==“false”。这是正确的。
那么使用感叹号的技巧是什么呢?当我们对文件进行测试时,它只会反转结果吗?

uqxowvwt

uqxowvwt1#

tl;dr
[ ! $bar ]$bar视为 * 字符串 任何非空 * 字符串都被认为是“true”-包括文字false;换句话说:[ ! 'true' ] && [ ! 'false' ]both 的结果都是“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 * 没有显式的布尔数据类型 *。
一元运算符!将其操作数 * 隐式地 * 解释为布尔值,布尔上下文
中的 * 字符串 * 解释如下:

  • 只有 * 空 * 字符串被认为是“假”**(退出代码1(!))
    • 任何非空 * 字符串**-包括 * 文字 * false--都被认为是**“true”**(退出代码0(!))

因此,! $bar的计算结果为“false”,因为$bar(包含非空字符串'false')的计算结果为“true”,而!将其反转。
!也可以在条件之外直接否定命令的成功状态(包括[)。
由于falsetrue也以 * 命令名 * 的形式存在(通常是作为shell内置程序),因此您可以 * 执行以下操作,但请注意,它仅适用于字面量为falsetrue的变量值:

bar=false
if ! "$bar"; then
   echo 'bar is false'
else
   echo 'bar is true'
fi

背景信息

类POSIX shell只有两种基本的(标量)数据类型:

  • 字符串(默认情况下):
  • [ ... ][[ ... ]]条件中,运算符=(Bash中的==),<<=>>=执行 * 字符串 * 比较。
  • 整数:
  • [ ... ][[ ... ]]条件中,必须使用不同的 * 算术 * 运算符(-eqltlegtge)来执行 * 数值 * 比较
  • 或者,在算术展开式($(( ... )))中,==<<=>>=具有其通常的 * 数字 * 含义。

在Bash中,您还可以使用(( ... ))作为算术 * 条件 *。
注意:根据POSIX,你不能 type 一个变量作为一个整数(因为没有办法 * 声明 * 一个shell变量),所以它只在使用算术运算符的比较中/在算术上下文中隐式地 * 被视为一个 *。
然而,在Bash中,你可以用declare -i/local -i * 声明 * 整型变量,但是在条件/算术上下文中,仍然是操作符/算术上下文的选择决定了值是被当作字符串还是整数。
shell中的布尔值被 * 隐式地 * 表示为 * 退出代码 *,这是通常的布尔到整数Map的 * 反转 *:

  • “true”Map到退出代码0(!)
  • “false”表示为退出代码1(!)或任何其他 * 非零 * 退出代码。
vi4fp9gy

vi4fp9gy2#

有关[test实用程序的可移植使用的详细信息,请参阅test的POSIX规范。
如果你使用[ ! $bar ],你是在玩火。

  • 如果$bar是一个空字符串,它退化为一个参数形式的test,该参数为!,并成功退出,因为!不是一个空字符串。
  • 如果$bar不是空字符串,则参数为!$bar的值,这将确定非空字符串是非空的,然后反转条件,因此它以失败状态退出。

你应该正常地写[ ! "$bar" ],如果$bar为空,它将正常工作。您可以(可以说应该)使用显式测试:

  • [ -z "$bar" ]用于测试空(零长度)字符串,以及
  • [ -n "$bar" ]测试非空字符串

但为了避免混淆,引号是必须的n on-empty和z ero-length是助记词。

$ 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

它将(可能)帮助你了解发生了什么。不过,输出相当冗长。

lstz6jyr

lstz6jyr3#

if测试命令的结果,不能直接测试变量的值。在本例中,您将它与test/[命令结合使用,后者是一个普通命令,可以在任何地方使用。

[ -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

case "$var" in
   some-string)
     dostuff
   ;;
esac

请注意,您可以使用!否定test/[的结果。

if ! [ -z "$var" ]; then
    do-something
fi

否定了这个条件。
但是,!也可以作为test/[的参数

if [ ! -z "$var" ]; then
    do-something
fi

意思是一样的

相关问题