bash if-a vs-e选项

bash if-a vs-e选项,bash,Bash,中的关于-a和-e选项均表示: 为了找出区别,我运行了以下脚本: 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} ] ;

中的关于
-a
-e
选项均表示:

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

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\u wheleph/Results
存在并且是一个目录。这就是我得到的:

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

-e
-a
因此:

  • -a
    -e
    选项之间有什么区别
  • 为什么
    -a
    在单括号内使用时会产生奇怪的结果

  • 我研究过了,这很毛茸茸的:

    -a
    已弃用,因此不再列在
    /usr/bin/test
    的手册页中,但仍然列在bash的手册页中。使用
    -e
    。对于单个“[”,bash内置函数的行为与
    test
    bash内置函数相同,后者的行为与
    /usr/bin/[/code>和
    /usr/bin/test
    相同(一个是另一个的符号链接)注意<代码> -<代码>的位置取决于它的位置:如果它在开始,它意味着<代码>文件存在。如果它位于两个表达式的中间,则意味着逻辑<代码>和<代码> >

    [!-a/path]&&echo exists
    不起作用,因为bash手册指出,
    -a
    在那里被认为是一个二进制运算符,因此上面的内容不是解析为
    否定-a..
    而是解析为
    如果'!'和'/path'为true
    (非空)。因此,脚本总是输出
    “-a”
    (实际上是测试文件)和
    “!-a”
    ,实际上是二进制的


    对于
    [[
    -a
    不再用作二进制
    &&
    ),因此它的唯一用途是检查那里的文件(尽管已弃用)。因此,否定实际上实现了您所期望的功能。

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

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

    注: 当您使用“[”时,bash确实会调用/bin/[


    错误显示bash调用[。strace还显示“execve”(/usr/bin/[”,“…”

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

    autoconf
    系统建议您避免使用“
    -a
    ”,因为它会引起混淆;现在我明白了原因。事实上,在便携式shell编程中,最好将这些条件与“
    &&
    ”或“
    |
    ”结合使用

    我认为@litb的思路是正确的。当您有“
    !-a${resin\u dir}
    ”时,Bash可能会将其解释为“is the string”!”非空且是“${resin\u 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
    $
    

    bash内置函数在一元模式下使用-a as-e,在二进制模式下使用-a as和。使用[[]]调用bash内置函数,这就是为什么您可以使用它获得合理的输出。如前所述,单括号调用接受一元但不正确处理它的测试二进制文件(应作为二进制文件使用)。实际上很少有shell调用/bin/test(或/bin/[)当你写“如果[…]”的时候。很久以前-是的;现在,不是。甚至香草Bourne shell都不是。是的,我认为shell内置代码总是优先考虑“[”对于bash来说根本不是内置代码。请看我在回答中的注释错误:[js@HOST2cpp]$help[[:[arg…]这是“测试”的同义词“内置,但最后一个参数必须是文字<代码>]',以匹配开头<代码>['[js@HOST2cpp]$alias foo bash:别名:foo:未找到[js@HOST2cpp]$这是否意味着alias现在是一个extern命令?不,它仍然是一个内置命令:)该死,好的:)。但是,删除bash脚本会显示“execve(“/usr/bin/[“,…有趣的是:在Solaris上,使用我的答案中的'truss-obash.truss-bash…',然后使用'grep-n exec bash.truss'只显示第1行执行bash本身。所以这很奇怪。(在Solaris上也没有/usr/bin/[在Solaris上-有一个/usr/bin/test。)
    $ [ $UNASIGNED_VAR == "bar" ]
    bash: [: ==: unary operator expected
    
    $ 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
    $