Bash中的[和[[有什么区别?

546

我查看了bash的man页面,发现[[使用条件表达式。然后我查看了条件表达式部分,发现它列出了与test(以及[)相同的运算符。

所以我想知道,在Bash中[[[之间有什么区别?


@AnthonyRutledge 你能更具体地说明你所指的是哪个,并解释为什么吗? - xdavidliu
5
对于任何想知道如何查看 -n-z-ge-eq-d 等 man 手册的人,答案是 man test - Gabriel Staples
4个回答

816

[[是bash对[命令的改进。它有几个增强功能,使其成为编写针对bash脚本的更好选择。我最喜欢的是:

  1. It is a syntactical feature of the shell, so it has some special behavior that [ doesn't have. You no longer have to quote variables like mad because [[ handles empty strings and strings with whitespace more intuitively. For example, with [ you have to write

    if [ -f "$file" ]
    

    to correctly handle empty strings or file names with spaces in them. With [[ the quotes are unnecessary:

    if [[ -f $file ]]
    
  2. Because it is a syntactical feature, it lets you use && and || operators for boolean tests and < and > for string comparisons. [ cannot do this because it is a regular command and &&, ||, <, and > are not passed to regular commands as command-line arguments.

  3. It has a wonderful =~ operator for doing regular expression matches. With [ you might write

    if [ "$answer" = y -o "$answer" = yes ]
    

    With [[ you can write this as

    if [[ $answer =~ ^y(es)?$ ]]
    

    It even lets you access the captured groups which it stores in BASH_REMATCH. For instance, ${BASH_REMATCH[1]} would be "es" if you typed a full "yes" above.

  4. You get pattern matching aka globbing for free. Maybe you're less strict about how to type yes. Maybe you're okay if the user types y-anything. Got you covered:

    if [[ $ANSWER = y* ]]
    
记住这是bash扩展,所以如果你在编写sh兼容脚本,则需要使用[。如果使用双括号,请确保您的脚本有#!/bin/bash shebang行。

另请参阅


23
不错,除了 [[ 还存在于 ksh 和最近的 POSIX sh 规范中。 - Darron
1
值得一提的是,可以放在[[[内部的条件表达式集合(如-f-z等)的参考资料位于Bash 条件表达式手册 - ShreevatsaR
@Darron 我正在使用特定服务器上的Ubuntu,并且我的sh(实际上是dash版本0.5.8)不支持[ [。 - Henrique
1
@Darron 在这里 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#:~:text=2.4%20Reserved%20Words 中存在,但是行为没有被指定,因此在需要 POSIX 兼容性时不能依赖它。 - VaNa

49
  • [test内置命令功能相同,并像test二进制文件一样工作(参见"man test")。
    • 在许多类UNIX环境中,其他基于sh的shell中的[基本上是一样的。
    • 只支持单个条件。 使用bash的&&||运算符进行多个测试必须分别放在不同的括号内。
    • 不支持原生的“非”运算符。 要反转条件,请使用第一个括号外的!来使用Shell的反转命令返回值的功能。
    • ==!=是字面字符串比较。
  • [[是bash的特性:
    • 是bash特有的,尽管其他shell可能已经实现了类似的结构。 不要期望在老式UNIX sh中看到它。
    • ==!=应用bash模式匹配规则,请参见"Pattern Matching" in man bash
    • 具有=~正则表达式匹配运算符
    • 允许在方括号内使用圆括号和!&&||逻辑运算符来组合子表达式。

除此之外,它们非常相似--它们之间的大多数单个测试工作方式是相同的,只有在需要使用逻辑AND/OR/NOT操作组合不同的测试时才会变得有趣。


14
测试支持使用 -a 和 -o 多个条件。此外,它还有一个非运算符,例如:如果 [ ! -z x ]; then echo Y; fi。 - Marco d'Itri
一个小细节。[[来自ksh。许多bash的“扩展”只是ksh的功能。 - Dan Christian

29

最重要的区别将是您的代码的清晰度。是的,上面所说的是真的,但[[ ]]使您的代码与高级语言中的预期相一致,特别是关于AND (&&)、OR (||)和NOT (!)运算符。因此,当您在不同系统和语言之间移动时,您将能够更快地解释脚本,这使您的生活更轻松。从一个好的UNIX/Linux参考手册中了解细节。在某些情况下,您可能会发现其中一些细节很有用,但您总是会欣赏清晰的代码!您更喜欢阅读哪个脚本片段?即使是超出上下文,第一个选择也更容易阅读和理解。


if [[ -d $newDir && -n $(echo $newDir | grep "^${webRootParent}") && -n $(echo $newDir | grep '/$') ]]; then ...
或者
if [ -d "$newDir" -a -n "$(echo "$newDir" | grep "^${webRootParent}")" -a -n "$(echo "$newDir" | grep '/$')" ]; then ...

2
尽管其他答案在技术上是正确的,但这是唯一完全正确的答案。 - Software Engineer
“最重要的区别将是您代码的清晰度。”:“不,区别在于[是一个命令,而[[是一个语法元素(“保留字”)。因此解析不同。” - U. Windl
不是吗?我只是在谈论实际上的区别。如果我没记错,[[ ]]let 的快捷方式。归根结底,确实存在语法上的差异,但对于普通人来说,易读性和可维护性才是最重要的。因此,这就是为什么我说“最重要”,而不是“唯一”或“按照书本规定”的区别。 - Anthony Rutledge
@AnthonyRutledge,它是 (( )),类似于 let。但这仅适用于算术计算,而不仅仅是布尔逻辑。 - Johan Boulé
@JohanBoulé 我喜欢使用 (( )) 进行算术运算。 - Anthony Rutledge

7
在bash中,与[不同的是,[[防止变量值的单词拆分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接