[[ condition ]]
使用and[ condition ]
或(( condition ))
and有什么区别( condition )
?在什么情况下我们需要使用其中任何一个?
(( 10 > 9 ))
有用但(( 10 -gt 9 ))
没用[[ 10 -gt 9 ]]
有用但[[ 10 > 9 ]]
没用
答案1
((...))
是 shell 的算术构造。可以使用的运算符已记录在手册中:6.5 Shell 算术
(...)
是分组在子 shell 中执行所含命令的构造:3.2.4.3 分组命令
[...]
是“遗留”条件构造。文档位于6.4 Bash 条件表达式
[[...]]
执行该[...]
执行的所有操作。不同之处在于,不会对内部变量执行分词和全局扩展,[[...]]
因此引用变量并不那么重要。此外,[[
可以执行模式匹配与==
运营商和正则表达式匹配与=~
操作员。
给出你意想不到的结果的原因[[ 10 > 9 ]]
是>
里面的运算符[[...]]
是字符串比较并且字符串“10”小于字符串“9”。
答案2
关于((…))
和(…)
正如所述另一个答案,((…))
是 shell 的算术构造(一个巴什主义) 并(…)
在子 shell 中运行命令。它们彼此之间以及与[ … ]
或之间有很大不同[[ … ]]
。
另一方面,[ … ]
和[[ … ]]
在简单情况下非常相似;它们可能会混淆。本回答的其余部分集中在[ … ]
和上[[ … ]]
。
正式说明
我的目标是:
- 详细说明
[ … ]
和之间的差异和相似之处[[ … ]]
; [ … ]
提供vs主题中的规范答案,因此可以用“不是”[[ … ]]
来回答的问题可以链接在这里;[
[[
- 提供足够详尽的答案,这样用户就不会再倾向于发布只关注单个差异的答案。
什么是[
?
[
进行测试。的目的
[
是测试某些东西(例如某个文件是否存在),如果测试成功则返回退出状态零,否则返回非零。[
是一个命令。[
是命令名称,例如cat
或echo
。[
(例如echo
)是 Bash 中的内置命令,但这仅意味着它可以在不产生额外进程的情况下运行,它仍然表现得像命令。[
您的系统中可能有一个独立的可执行文件(例如/bin/[
);尝试type -a [
在 Bash 中找出答案。[
后面需要一个空格。作为命令,
[
带参数。与任何其他命令一样,参数必须彼此分开,并与命令名称分开。[foo
是不同的命令名称,它不等同于[ foo
(类似且更明显echoHello world
不是echo Hello world
)。您当然需要在 后面加一个空格(或制表符)[
。[
需要]
。[
需要]
作为最后一个参数,否则它将无法工作。这只是为了使它[ … ]
作为一个块突出,就像是某种特殊语法一样;但它不是一种特殊语法。要]
作为最后一个参数传递,您需要在它前面有一个空格(或制表符)。作为比较:中的最后一个参数[ … bar]
是,bar]
它不是]
,所以[ … bar]
不是一个有效的命令。[
(几乎)像test
。[ … ]
相当于test …
。换句话说,您可以通过删除并更改命令名称将任何[
命令转换为命令。并且您可以通过更改命令名称并添加 ,将任何命令转换为命令。test
]
test
[
]
[
没有什么特别的。记住这一点很好
[
,它并不特殊,它只是一个命令的花哨名字。如果你承认这一点,那么你就不会对以下事实感到惊讶:全部shell 所做的解析和处理前如果命令是 ,则运行命令( 或 等)也会发生这种情况。特别test
是:echo
ls
[
[
不知道您是否引用了它的任何参数,它会在 shell 删除引号后获取参数。未加引号且未转义
&&
,或者||
介于[
和之间]
,不被解释为 的参数[
。换句话说,[ … || … ]
被解释为[ …
(无效,因为没有]
)和… ]
(单独的命令,无论…
是什么)与 逻辑上相连||
,与 完全一样command1 || command2
。
[
由 POSIX 指定。有POSIX 规范
[
/test
。可以打电话[
便携。注意:- 有些主要代码是扩展,有些则被标记为过时。例如,我们的无效代码 (
[ … || … ]
) 可以修复为[ … -o … ]
,但由于-o
已过时,因此更好的修复方法是[ … ] || [ … ]
。 - 实现可能支持更多主要项。Bash
[
中的内置命令支持(请参阅help test
);操作系统中的[
二进制文件(如)可能支持(请参阅)。/bin/[
man test
- 有些主要代码是扩展,有些则被标记为过时。例如,我们的无效代码 (
什么是[[
? 和 有何[[
不同[
?
注意:
- 该问题已加标签狂欢,现在我们谈论的是[[
在 Bash 中.——
本节中编号的段落与上一节中编号的段落相对应。
(相似)
[[
进行测试。的目的
[[
是测试某些东西(例如某个文件是否存在),如果测试成功则返回退出状态零,否则返回非零。[[
可以测试任何东西[
,等等。(不同之处)
[[
是一个关键词。是
[[
一个 shell 关键字(type [[
在 Bash 中调用以确认这一点)。与[
内置命令一样,该[[
关键字属于 Bash;但它才不是表现得像一个命令。(相似)
[[
后面需要一个空格。(或标签)。
(相似)
[[
需要]]
。[[
需要]]
在代码中稍后添加,但这不仅仅是为了[[ … ]]
突出块。这是一种特殊的语法(一个区别,我们稍后会讲到)。你需要在 之前加一个空格(或制表符)]]
。(不同之处)没有看起来与 等效的普通命令
[[
。没有其他命令/关键字/任何东西能够以替换
[[
的方式test
进行替换[
。(不同之处)
[[
是特别的。[[
更改 shell 解析和解释代码的方式,直到匹配为止。shell 在运行或(或等)]]
之前进行的正常解析和处理不适用于内部。特别是:[
test
echo
ls
[[ … ]]
(不同之处)
[[
POSIX 没有指定。不可
[[
移植。[[
在 Bash 中有效,但在纯 中无效sh
。其他 shell 可能支持[[
(例如 Zsh 支持),但它们[[
可能与[[
Bash 的不同。[[
并非旨在遵守[
/的规范test
。在许多情况下,替换[
with[[
和]
with]]
会为您提供[[ … ]]
与原始[ … ]
代码片段等效的代码片段;但并非总是如此,有时内部需要调整。所以不要盲目改[
。[[
盲目改[[
更[
危险,因为有些测试[[
可以做,有些测试[
不能做。
其他说明:
语法中既不是
[
也不是。请记住,它只是测试一些代码的退出状态。是有效的,是有效的,类似地,或也是有效的(如果或部分本身是有效的代码片段)。[[
if … then …
if
if true; then …
if sleep 5; then …
if [ … ]; then …
if [[ … ]]; then …
[ … ]
[[ … ]]
由于
((…))
或(…)
也返回一些退出状态(取决于里面的内容),所以也可以在之后使用if
。我个人更喜欢使用任何可以轻松完成的
[
测试,在真正需要时才使用。这样我就不会习惯不可移植,而且我知道在不如 Bash 丰富的 shell 中我可以做什么。[
[[
[[
操作系统中的可执行文件
[
不一定严格等同于[
Bash 中的内置命令。如果[
由 Bash 调用,则内置命令将执行该任务。如果[
由其他程序调用,则可执行文件将执行该任务。例如find … -exec [ … ] …
使用可执行文件。没有标准的[[
可执行文件(至少在我所知道的系统中),因此find … -exec [[ … ]] …
永远不会起作用。如果存在[[
可执行文件,则它必须表现得像命令,它无法模仿关键字。
答案3
[ ] 和 [[ ]] 之间有很大区别:
a=0;
if [ $a = 1 -a $(grep ERR 1.log|wc -l) -ne 0 ];then
echo "error";
fi
当使用 [ ] 时,与运算符 -a 不支持短路求值。在上面的代码中,即使第一个条件返回 false,第二个条件仍然会被求值。如果文件 1.log 不存在,它会报错“没有这样的文件或目录”。
但对于 [[ ]]:
a=0
if [[ $a = 1 && $(grep ERR 1.log|wc -l) -ne 0 ];then
echo "error"
fi
即使文件“1.log”不存在,也无妨,因为第一个条件为假,所以第二个条件将不会被评估。
答案4
我本来想把这个写在评论中,但现在还不允许。
我注意到 [] 和 [[]] 之间的一个区别是,前者可以使用多重比较。
相同的比较在 [[]] 中引发语法错误
a=1
b=2
这有效:
$ [ "$a" -gt 0 -a "$b" -gt "$a" ] && { echo '[b>a>0]'; }
[b>a>0]
这不起作用:
$ [[ $a -gt 0 -a $b -gt $a ]] && { echo '[[b>a>0]]'; }
-bash: syntax error in conditional expression
-bash: syntax error near `-a'
我还没有真正深入研究为什么会这样,但是在使用多重比较时,我使用 []。