bash - if 语句中的括号有什么作用?

bash - if 语句中的括号有什么作用?

也许这不仅仅适用于 bash,但我对 if 语句中括号的作用感到困惑。最多例子似乎有以下格式

if [ expression ]; then
    #do stuff
fi

但这并不总是对我有用。例如我有以下脚本test.sh

#!/bin/bash

flag=False
if ! $flag; then
    echo "No brackets: Flag is $flag"
fi
if [ ! $flag ]; then
    echo "With brackets: Flag is $flag"
fi
echo "The end."

哪个打印

$ ./test.sh
No brackets: Flag is False
The end.

因此,使用括号的语句要么被忽略,要么计算结果为 False。为什么会出现这种情况?括号有什么作用?

我还见过双括号。那些是如何使用的?

--

编辑:声称重复的问题()只回答这个问题的一小部分。我仍然不清楚为什么带括号的语法会失败(在我看来,test ! false应该评估为true)以及为什么不带括号的语法会成功(尽管,正如 @ilkkachu 在评论中提到的,似乎它实际上也应该失败? )。

答案1

在除具有不区分大小写的文件系统(如 macOS)之外的任何 Unix 上,该if语句

if ! $flag; then
    echo "No brackets: Flag is $flag"
fi

将生成输出

bash: False: command not found
No brackets: Flag is False

在 macOS 上,由于文件系统不区分大小写,因此不会生成该错误,因为该False命令与标准(外部)命令相同。false

无论哪种情况,测试! $flag都是正确的(但出于不同的原因),因此文本被打印。在大多数 Unices 上,! $flag为 true,因为它运行False命令,失败,并且失败被否定。在 macOS 上,它运行外部false实用程序,该实用程序返回 false,即否定。

第二个if声明,

if [ ! $flag ]; then
    echo "With brackets: Flag is $flag"
fi

在任何 Unix 上都以相同的方式工作。它使用两个参数和来调用[实用程序,该实用程序与实用程序相同test(但[需要匹配作为其最后一个操作数) 。默认情况下,如果字符串参数具有非零长度(它具有非零长度),则将返回 true 值,但它会被so返回 false 否定,并且永远不会执行。]!Falsetest!testecho

为了清楚起见,最好使用测试-n来测试非空字符串:

if [ -n "$flag" ]; then ...

-z测试空字符串:

if [ -z "$flag" ]; then ...

变量扩展的引用在这段特定的代码中并不重要,因为$flag扩展为不是文件名通配模式的单个单词。但一般来说,变量扩展应该用双引号引起来,以避免分词和文件名通配。

[有关vs. 的讨论[[,请参阅

有关的:

答案2

确切的答案有点复杂。归根结底,要理解这个词false既是命令又是字符串(取决于上下文)。

更长的描述:

让我们从字符串开始A_Non_Existing_Command

str=A_Non_Existing_Command

所以,a(一般来说:请引用变量扩展。)

$ if $str; then echo yes; else echo no; fi
bash: A_Non_Existing_Command: command not found
no

会打印,因为执行的命令失败(它不存在)并且 else 部分被执行。当然,还有一个错误消息(稍后会详细介绍)。

但是,测试命令testor [help test在 bash 内部读取)将测试是否:

括号之间的字符串长度非零

所以:

$ if [ "$str" ]; then echo yes; else echo no; fi
yes

打印 yes(因为字符串具有非零数量的字符(通常是字节))。该字符串也是不存在的命令的名称并不重要。在这种情况下,变量的值被解释(计算)为字符串。

当然,负面测试将打印 no:

$ if [ ! "$str" ]; then echo yes; else echo no; fi
no

这完全等同于[ -z "$str" ].

现在,将str内容更改为False并执行相同的命令:

 $ str=false
 $ if     "$str"  ; then echo yes; else echo no; fi
 no

 $ if [   "$str" ]; then echo yes; else echo no; fi
 yes

 $ if [ ! "$str" ]; then echo yes; else echo no; fi
 no

如果您得到相同的结果str=False(没有错误),可能是因为您所在的系统具有不区分大小写的文件系统(搜索 False 将找到 false,没有任何错误)。

相关内容