test 或 [ 或 [[ 在 bash shell 和其他 shell 之间更便携吗?

Mic*_*ant 47 shell posix portability test

我知道我可以

$ [ -w /home/durrantm ] && echo "writable"
writable
Run Code Online (Sandbox Code Playgroud)

或者

$ test -w /home/durrantm && echo "writable"
writable
Run Code Online (Sandbox Code Playgroud)

或者

$ [[ -w /home/durrantm ]] && echo "writable"
writable
Run Code Online (Sandbox Code Playgroud)

我喜欢使用第三种语法。它们在所有方面以及所有负面和边缘情况下都等效吗?可移植性是否有任何差异,例如 Ubuntu 上的 bash 和 OS X 上的 bash 或较旧/较新的 bash 版本,例如 4.0 之前/之后,它们是否都以相同的方式扩展表达式?

ter*_*don 35

是的,存在差异。最便携的是test[ ]。这些都是POSIXtest规范的一部分。

if ... fi构造也由 POSIX 定义,并且应该是完全可移植的。

[[ ]]是一个ksh功能,它也存在于某些版本bash所有现代的),在zsh也许在别人,但不存在shdash或其他各种简单的炮弹。

因此,要使您的脚本可移植,请使用[ ],testif ... fi.

  • 需要注意的是,`bash` 和 `zsh` 已经支持 `[[` 很长时间了(`bash` 是在 90 年代后期添加的,`zsh` 不迟于 2000 年,如果它我会感到惊讶 * ever* 缺乏支持),因此您不太可能遇到没有 `[[` 的版本。遇到不同的 POSIX 兼容 shell(例如“dash”)的可能性要大得多。 (10认同)
  • @helpermethod 也是,内置正则表达式`[[ $a =~ ^reg.*exp.*$' ]]` (2认同)

Cos*_*tas 31

[test命令的同义词,它同时是bash 内置命令和单独命令。但[[是一个bash 关键字,仅在某些版本中有效。因此,出于便携性的原因,您最好使用单个[]test

[ -w "/home/durrantm" ] && echo "writable"
Run Code Online (Sandbox Code Playgroud)

  • `[`是 POSIX 内置还是 Bash 内置? (2认同)

rus*_*ush 20

请注意,这[] && cmdif .. fi构造不同。

有时它的行为非常相似,您可以使用[] && cmd代替if .. fi. 但只是有时。如果您有多个命令来执行 if 条件,或者您需要if .. else .. fi小心并注意逻辑。

几个例子:

[ -z "$VAR" ] && ls file || echo wiiii
Run Code Online (Sandbox Code Playgroud)

不一样

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi
Run Code Online (Sandbox Code Playgroud)

因为 ifls将失败,echo将被执行,而if.

另一个例子:

[ -z "$VAR" ] && ls file && echo wiii
Run Code Online (Sandbox Code Playgroud)

不一样

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi
Run Code Online (Sandbox Code Playgroud)

虽然这个结构会起到同样的作用

[ -z "$VAR" ] && { ls file ; echo wiii ; }
Run Code Online (Sandbox Code Playgroud)

请注意;echo 很重要并且必须在那里。

所以上面的恢复语句我们可以说

[] && cmd == 如果第一个命令成功则执行下一个命令

if .. fi == if 条件(也可能是测试命令)然后执行命令

因此,仅用于[[[使用之间的便携性[

if与 POSIX 兼容。因此,如果您必须在两者之间做出选择[if选择查看您的任务和预期行为。


IMS*_*SoP 10

它实际上&&是替换if, 而不是test: ifshell 脚本中的语句测试命令是否返回“成功”(零)退出状态;在您的示例中,命令是[.

因此,这里实际上有两件事要改变:用于运行测试的命令,以及用于根据测试结果执行代码的语法。

测试命令:

  • test是用于评估字符串和文件属性的标准化命令;在您的示例中,您正在运行命令test -w /home/durrantm
  • [是该命令的别名,同样标准化,它有一个强制的最后一个参数,]以便看起来像一个括号表达式;不要被愚弄了,它仍然只是一个命令(你甚至可能会发现你的系统有一个名为 的文件/bin/[
  • [[是一些 shell 中内置的 test 命令的扩展版本,但不是同一 POSIX 标准的一部分;它包括您在此处未使用的额外选项

条件表达式:

  • &&操作者(这里标准化)进行逻辑与运算,通过评估两个命令并返回0(表示真),如果他们都返回0; 如果第一个命令返回零,它只会评估第二个命令,因此它可以用作简单的条件
  • if ... then ... fi构建体(此处标准化)使用判定“真”的相同的方法,但允许语句的在化合物列表then条款,而不是由一个提供的单个命令&&的短路,并提供elifelse子句是很难写仅使用&&||请注意,if语句中的条件周围没有括号

因此,以下都是同样可移植且完全等效的示例效果图:

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

虽然以下也是等效的,但由于 的非标准性质而不太便携[[

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi


PM *_*ing 7

为了便于携带,请使用test/ [。但是,如果您不需要可移植性,为了您自己和其他阅读您脚本的人的理智,请使用[[. :)

也看到What is the difference between test, [ and [[ ?BashFAQ


Sté*_*las 7

如果您想在类似 Bourne 的世界之外具有可移植性,那么:

test -w /home/durrantm && echo writable
Run Code Online (Sandbox Code Playgroud)

是最便携的。它适用于伯恩cshrc家庭的贝壳。

test -w /home/durrantm && echo "writable"
Run Code Online (Sandbox Code Playgroud)

将输出"writable"而不是writable在系列的 shell 中rcrc, es, akanga, where "is not special)。

[ -w /home/durrantm ] && echo writable
Run Code Online (Sandbox Code Playgroud)

在没有命令的系统上的cshrc系列的shell 中不起作用(已知某些具有但没有它的别名)。[$PATHtest[

if [ -w /home/durrantm ]; then echo writabe; fi
Run Code Online (Sandbox Code Playgroud)

仅适用于伯恩家族的贝壳。

[[ -w /home/durrantm ]] && echo writable
Run Code Online (Sandbox Code Playgroud)

仅适用于ksh(起源地)zshbash(伯恩家族中的所有 3 个)。

没有一个可以fish在你需要的shell 中工作:

[ -w /home/durrantm ]; and echo writable
Run Code Online (Sandbox Code Playgroud)

或者:

if [ -w /home/durrantm ]; echo writable; end
Run Code Online (Sandbox Code Playgroud)