Bash if-a vs-e 选项

关于 Bash 文档中的 -a-e选项,都说:

-a file
True if file exists.
-e file
True if file exists.

为了找出区别,我运行了下面的脚本:

resin_dir=/Test/Resin_wheleph/Results


if [ -e ${resin_dir} ] ; then
echo "-e ";
fi


if [ ! -e ${resin_dir} ] ; then
echo "! -e";
fi


if [ -a ${resin_dir} ] ; then
echo "-a";
fi


if [ ! -a ${resin_dir} ] ; then
echo "! -a";
fi

/Test/Resin_wheleph/Results存在并且是一个目录:

-e
-a
! -a

这似乎有点奇怪(注意 -a! -a)。但是当我在类似的脚本中使用双括号(例如 if [[ -e ${resin_dir} ]])时,它会给出合理的输出:

-e
-a

所以:

  1. -a-e选项的区别是什么?
  2. 为什么在单括号内使用 -a会产生一个奇怪的结果?
86287 次浏览

我研究过了,这很棘手:

-a已被废弃,因此不再列在 /usr/bin/test的手册中,但仍然列在 bash 的手册中。使用 -e。对于单个“[”,bash 内建的行为与 test bash 内建的行为相同,后者与 /usr/bin/[/usr/bin/test的行为相同(一个是到另一个的符号链接)。注意,-a的效果取决于它的位置: 如果它是在开始,它意味着 file exists。如果它在两个表达式中间,则表示逻辑 and

正如 bash 手册指出的那样,[ ! -a /path ] && echo exists不起作用,因为 -a在那里被认为是二进制操作符,所以上述操作符不被解析为 negate -a ..,而是被解析为 if '!' and '/path' is true(非空)。因此,脚本总是输出 "-a"(实际上是测试文件)和 "! -a"(实际上是二进制 and)。

对于 [[-a不再作为二进制 and使用(&&在那里使用) ,因此它的独特用途是检查那里的文件(尽管不推荐)。所以,否定实际上达到了你的期望。

双括号[[ exp ]]是 bash 内置的。在 bash-a 和-e 中是相同的,可能是为了某种向后兼容性。

单括号[ exp ]是外部命令“ test”的别名。在“ test”中,-a 是一个逻辑 AND。虽然[ nothing AND $STRING ]看起来应该是 false,但 test 有一些语法上的问题,这就是为什么我推荐使用 bash builtin [[ exp ]] ,它往往更理智。

注: Bash 在使用“[”时确实调用/bin/[。

$ [ $UNASIGNED_VAR == "bar" ]
bash: [: ==: unary operator expected

错误显示名为[ . strace 也显示“ Executive (”/usr/bin/[”,...”

测试运算符的“ -a”选项有一个作为一元运算符的含义,另一个作为二元运算符的含义。作为二进制运算符,它是‘ and’连接词(而‘ -o’是‘ or’连接词)。作为一元操作符,它显然测试文件的存在。

autoconf系统建议您避免使用“ -a”,因为它会造成混淆; 现在我知道为什么了。事实上,在可移植 shell 编程中,最好将条件与“ &&”或“ ||”结合起来。

我认为@litb 的方向是正确的。当您有了‘ ! -a ${resin_dir}’,Bash 可能会将其解释为‘ is the string’!’非空,是’${ resin _ dir }’中的字符串非空,答案是肯定的。Korn shell 对此有不同的视图,Bourne shell 也有不同的视图——所以远离‘ -a’。

索拉里斯10:

$ bash -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
Bad
$ ksh -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
OK
$ sh -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
sh: test: argument expected
$