Bash 中 [[ ]] 与 [ ] 或 (( )) 与 ( ) 之间的区别

Bash 中 [[ ]] 与 [ ] 或 (( )) 与 ( ) 之间的区别

[[ 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主题中的规范答案,因此可以用“不是”[[ … ]]来回答的问题可以链接在这里;[[[
  • 提供足够详尽的答案,这样用户就不会再倾向于发布只关注单个差异的答案。

什么是[

  1. [进行测试。

    的目的[是测试某些东西(例如某个文件是否存在),如果测试成功则返回退出状态零,否则返回非零。

  2. [是一个命令。

    [是命令名称,例如catecho[(例如echo)是 Bash 中的内置命令,但这仅意味着它可以在不产生额外进程的情况下运行,它仍然表现得像命令。[您的系统中可能有一个独立的可执行文件(例如/bin/[);尝试type -a [在 Bash 中找出答案。

  3. [后面需要一个空格。

    作为命令,[带参数。与任何其他命令一样,参数必须彼此分开,并与命令名称分开。[foo是不同的命令名称,它不等同于[ foo(类似且更明显echoHello world不是echo Hello world)。您当然需要在 后面加一个空格(或制表符)[

  4. [需要]

    [需要]作为最后一个参数,否则它将无法工作。这只是为了使它[ … ]作为一个块突出,就像是某种特殊语法一样;但它不是一种特殊语法。要]作为最后一个参数传递,您需要在它前面有一个空格(或制表符)。作为比较:中的最后一个参数[ … bar]是,bar]它不是],所以[ … bar]不是一个有效的命令。

  5. [(几乎)像test

    [ … ]相当于test …。换句话说,您可以通过删除并更改命令名称将任何[命令转换为命令。并且您可以通过更改命令名称并添加 ,将任何命令转换为命令。test]test[]

  6. [没有什么特别的。

    记住这一点很好[,它并不特殊,它只是一个命令的花哨名字。如果你承认这一点,那么你就不会对以下事实感到惊讶:全部shell 所做的解析和处理如果命令是 ,则运行命令( 或 等)也会发生这种情况。特别test是:echols[

    • [不知道您是否引用了它的任何参数,它会在 shell 删除引号后获取参数。

    • 未加引号且未转义&&,或者||介于[和之间],不被解释为 的参数[。换句话说,[ … || … ]被解释为[ …(无效,因为没有])和… ](单独的命令,无论是什么)与 逻辑上相连||,与 完全一样command1 || command2

  7. [由 POSIX 指定。

    POSIX 规范[/test。可以打电话[便携。注意:

    • 有些主要代码是扩展,有些则被标记为过时。例如,我们的无效代码 ( [ … || … ]) 可以修复为[ … -o … ],但由于-o已过时,因此更好的修复方法是[ … ] || [ … ]
    • 实现可能支持更多主要项。Bash[中的内置命令支持(请参阅help test);操作系统中的[二进制文件(如)可能支持(请参阅)。/bin/[man test

什么是[[? 和 有何[[不同[

注意:
- 该问题已加标签,现在我们谈论的是[[ 在 Bash 中.——
本节中编号的段落与上一节中编号的段落相对应。

  1. (相似)[[进行测试。

    的目的[[是测试某些东西(例如某个文件是否存在),如果测试成功则返回退出状态零,否则返回非零。[[可以测试任何东西[,等等。

  2. (不同之处)[[是一个关键词。

    ​是[[一个 shell 关键字(type [[在 Bash 中调用以确认这一点)。与[内置命令一样,该[[关键字属于 Bash;但它才不是表现得像一个命令。

  3. (相似)[[后面需要一个空格。

    (或标签)。

  4. (相似)[[需要]]

    [[需要]]在代码中稍后添加,但这不仅仅是为了[[ … ]]突出块。这是一种特殊的语法(一个区别,我们稍后会讲到)。你需要在 之前加一个空格(或制表符)]]

  5. (不同之处)没有看起来与 等效的普通命令[[

    没有其他命令/关键字/任何东西能够以替换[[的方式test进行替换[

  6. (不同之处)[[ 特别的。

    [[更改 shell 解析和解释代码的方式,直到匹配为止。shell 在运行或(或等)]]之前进行的正常解析和处理不适用于内部。特别是:[testechols[[ … ]]

    • [[ 注意到你是否引用了它的任何“参数”。双引号变量是不必要的(虽然通常这是),但在某些情况下,用双引号括住字符串(或变量)会有所不同(参见这个答案=其中提到“或或==!=的右侧=~”)。

    • &&或和||之间属于构造。可以是一段有效的代码,实际上等同于。[[]][[ … ]][[ … || … ]][[ … ]] || [[ … ]]

  7. (不同之处)[[POSIX 没有指定。

    ​不可[[移植。[[在 Bash 中有效,但在纯 中无效sh。其他 shell 可能支持[[(例如 Zsh 支持),但它们[[可能与[[Bash 的不同。

    [[并非旨在遵守[/的规范test。在许多情况下,替换[with[[]with]]会为您提供[[ … ]]与原始[ … ]代码片段等效的代码片段;但并非总是如此,有时内部需要调整。所以不要盲目改[[[盲目改[[[危险,因为有些测试[[可以做,有些测试[不能做。


其他说明:

  1. 语法中既不是[也不是。请记住,它只是测试一些代码的退出状态。是有效的,是有效的,类似地,或也是有效的(如果或部分本身是有效的代码片段)。[[if … then …ifif true; then …if sleep 5; then …if [ … ]; then …if [[ … ]]; then …[ … ][[ … ]]

    由于((…))(…)也返回一些退出状态(取决于里面的内容),所以也可以在之后使用if

  2. 我个人更喜欢使用任何可以轻松完成的[测试,在真正需要时才使用。这样我就不会习惯不可移植,而且我知道在不如 Bash 丰富的 shell 中我可以做什么。[[[[[

  3. 操作系统中的可执行文件[不一定严格等同于[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'

我还没有真正深入研究为什么会这样,但是在使用多重比较时,我使用 []。

相关内容