[ vs [[ : 在 bash 脚本中使用哪一个?

kjo*_*kjo 8 bash zsh shell-script control-flow test

zsh 手册页在test(aka [)部分明确建议不要使用它,并敦促读者[[尽可能使用它。

相关章节中指出:

该命令尝试在指定的位置实现 POSIX 及其扩展。不幸的是,语法中存在内在的歧义;特别是测试运算符和类似它们的字符串之间没有区别。该标准试图解决这些问题的少量参数(最多四个);不能依赖五个或更多参数的兼容性。敦促用户尽可能使用[[没有这些歧义的“ ”测试语法。

我想我遇到过类似的 bash 建议,但是当我浏览 bash 手册页时,我找不到任何关于使用哪种表单([[[)的“官方”建议。(也许我错过了?)

除了向后兼容“旧外壳”之外,还有什么理由可以[在 bash 脚本中使用吗?或者换种方式,确实庆典保持[连同[[其原因其他比向后兼容?

gol*_*cks 6

不过也有一些细微的差别:

#!/bin/bash

eg=whatever

if [ $eg == what* ]; then   # file glob test
    echo '[]'
fi

if [[ $eg == what* ]]; then   # pattern match test
    echo "[[]]"
fi      
Run Code Online (Sandbox Code Playgroud)

除非当前目录中有一个名为“whatever”的文件,否则第一个测试不会通过,因为匹配是针对当前目录内容的文件 glob,而第二个是实际的字符串模式匹配。


H.-*_*itt 4

[优先选择[[if enough 的原因是它[在不同的 bash 版本之间更稳定。

man bash

兼容31

如果设置,bash 将其行为更改为 3.1 版关于 [[ 条件命令的 =~ 运算符的带引号参数的行为。

兼容32

如果设置,当使用 [[ 条件命令的 < 和 > 运算符时,bash 会将其行为更改为 3.2 版关于特定于区域设置的字符串比较的行为。bash-4.1 之前的 Bash 版本使用 ASCII 排序规则和 strcmp(3);bash-4.1 及更高版本使用当前语言环境的排序规则序列和 strcoll(3)。

兼容40

如果设置,则在使用 [[ 条件命令的 < 和 > 运算符(请参阅上一项)以及中断命令列表的效果时,bash 会将其行为更改为版本 4.0 的特定于区域设置的字符串比较。

也许对于有背景的用户来说也更常见一些ksh

关于性能的注意事项

'[[' 比 '[' 更快

  • 对于单个调用,速度差异没有可比的影响,并且您应该更喜欢内置的“[”。
  • 如果您在更大的循环结构中,您可能会考虑将 '[' 替换为 '[['

对于测量,您可以使用以下比较脚本

let upperBound=$1
echo "check [,  ${upperBound} iterations"
let i=0
time while [ $i -lt ${upperBound} ] ; do let i++ ; done

echo; echo;
echo "check [[, ${upperBound} iterations"
let i=0
time while [[ $i < ${upperBound} ]] ; do let i++ ; done
Run Code Online (Sandbox Code Playgroud)

比较脚本的结果

检查 [,1000 次迭代

真实 0m0.031s
用户 0m0.028s
系统 0m0.004s

检查 [[,1000 次迭代

真实 0m0.000s
用户 0m0.000s
系统 0m0.000s