bash if -a vs -e选项

whe*_*eph 54 bash

Bash文档中的 about -a-eoptions 都说:

-a file
    True if file exists.
-e file
    True if file exists. 
Run Code Online (Sandbox Code Playgroud)

试图找出差异,我运行了以下脚本:

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
Run Code Online (Sandbox Code Playgroud)

/Test/Resin_wheleph/Results存在并且是一个目录.这就是我得到的:

-e
-a
! -a
Run Code Online (Sandbox Code Playgroud)

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

-e
-a
Run Code Online (Sandbox Code Playgroud)

所以:

  1. -a-e选项有什么区别?
  2. -a在单支架内使用时为什么会产生奇怪的结果?

Joh*_*itb 67

我研究过,这很毛茸茸:

-a不推荐使用,因此不再在联机帮助页中列出/usr/bin/test,但仍然在bash中.使用-e.对于单个'[',bash内置行为与bash内置行为相同test,其行为/usr/bin/[/usr/bin/test(和一个是另一个的符号链接)相同.注意效果-a取决于它的位置:如果它在开始时,则意味着file exists.如果它位于两个表达式的中间,则表示逻辑and.

[ ! -a /path ] && echo exists不起作用,因为bash手册指出那里-a被认为是一个二元运算符,所以上面的解析不是a negate -a ..而是if '!' and '/path' is true(非空).因此,您的脚本始终输出"-a"(实际上测试文件),"! -a"这实际上是二进制文件and.

因为[[,-a不再用作二进制文件and(&&在那里使用),因此它的唯一目的是检查那里的文件(虽然被弃用).所以,否定实际上是你所期望的.


Jon*_*ler 5

-a测试运算符的 ' ' 选项作为一元运算符具有一种含义,作为二元运算符具有另一种含义。作为二元运算符,它是“和”连接词(而“ -o”是“或”连接词)。作为一元运算符,它显然是在测试文件是否存在。

autoconf系统建议您避免使用“ -a”,因为它会导致混乱; 现在我明白为什么了。的确,在可移植的shell 编程中,最好将条件与' &&' 或' ||'结合起来。

我认为@litb 走在正确的轨道上。当您有 ' ! -a ${resin_dir}' 时,Bash 可能会将其解释为“是字符串 '!' 非空并且是 '${resin_dir}' 中的字符串非空,答案是肯定的。Korn shell 对此有不同的看法,而 Bourne shell 则是另一种看法 - 所以远离 ' -a'。

在 Solaris 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
$
Run Code Online (Sandbox Code Playgroud)