也许这不仅仅适用于 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 否定,并且永远不会执行。]
!
False
test
!
test
echo
为了清楚起见,最好使用测试-n
来测试非空字符串:
if [ -n "$flag" ]; then ...
或-z
测试空字符串:
if [ -z "$flag" ]; then ...
变量扩展的引用在这段特定的代码中并不重要,因为$flag
扩展为不是文件名通配模式的单个单词。但一般来说,变量扩展应该用双引号引起来,以避免分词和文件名通配。
[
有关vs. 的讨论[[
,请参阅
有关的:
man test
在您的系统上以及help test
任何bash
shell 中。- 为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?
答案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 部分被执行。当然,还有一个错误消息(稍后会详细介绍)。
但是,测试命令test
or [
(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,没有任何错误)。