Bash 否定 -a(文件存在)不会改变结果,而 for ! -e 改变结果

Mar*_*020 16 bash test

我很困惑,但仍然猜想我以某种方式误解了 Bash。

/$ if [   -e /bin/grep ]; then echo yea; else echo nay ; fi
yea
/$ if [ ! -e /bin/grep ]; then echo yea; else echo nay ; fi
nay
/$ if [   -a /bin/grep ]; then echo yea; else echo nay ; fi
yea
/$ if [ ! -a /bin/grep ]; then echo yea; else echo nay ; fi
yea
Run Code Online (Sandbox Code Playgroud)

为什么否定!会逆转测试的效果-e而不是-a测试?

男人巴什 说:

测试

3 个参数

以下条件按列出的顺序应用。

  1. 如果第二个参数是上面条件表达式下列出的二进制条件运算符之一,则表达式的结果是使用第一个和第三个参数作为操作数的二进制测试的结果。当存在三个参数时,-aand运算符被视为二元运算符。-o
  2. 如果第一个参数是!,则该值是使用第二个和第三个参数进行双参数测试的否定。

Bash 条件表达式

[[ 条件表达式由复合命令以及test[内置命令使用

-a file
如果文件存在则为真。
-b file
如果文件存在并且是块特殊文件,则为 True。
-c file
如果文件存在并且是字符特殊文件,则为 True。
-d file
如果文件存在并且是目录,则为 True。
-e file
如果文件存在则为真。

Sté*_*las 29

-a既是一元运算符(对于a可访问性,添加是为了与 Korn shell 兼容,但在其他方面是非标准的,现在与 冗余-e)和二进制运算符(对于and,在 POSIX(使用 XSI)中,但在那里已弃用)运算符。

\n

这里按照 POSIX 的要求[ ! -a /bin/grep ]调用二元运算符。[ "$a" -a "$b" ]为了测试是否$a非空 $b非空,这里用$a==!$b== /bin/grep。由于两个字符串都非空,因此它返回true

\n

另请参阅您引用的文本中的“当存在三个参数时,-a 和 -o 运算符被视为二元运算符” 。

\n

-a一元和二进制形式均已弃用,一元形式是因为它被 取代-e,二进制形式是因为它会导致不可靠且不明确的测试表达式。

\n

要测试文件是否存在(尽管实际上,更多的是测试文件是否可访问,是否stat()会在路径\xc2\xb9 上成功),请使用[ -e filepath ]. To两个条件,&&在两次调用之间使用[

\n

为了测试字符串是否非空,我个人更喜欢表单[ -n "$string" ]而不是表单[ "$string" ]

\n

所以:

\n\n

根据(又名)实用程序的 POSIX 规范的基本原理test[

\n
\n

指定 -a 和 -o 二进制原色以及 \'(\' 和 \')\' 运算符的 XSI 扩展已被标记为过时。(许多使用它们的表达式\n由语法模糊地定义,具体取决于正在评估的特定表达式。)使用这些表达式\n的脚本应转换为下面给出的形式。尽管许多实现将继续支持这些过时的形式,但脚本在处理用户提供的输入时应该非常小心,因为这些输入可能会与这些以及其他原色和运算符混淆。

\n
\n

和:

\n
\n

早期的提案使用了 KornShell -a 主运算符(具有相同的含义),但后来将其更改为 -e,因为人们担心人们很可能将 -a 主运算符与 -a 二元运算符混淆。

\n
\n

yashbosh、 GNU的手册coreutils确实防止在各自的/实现中使用二进制-a/ ,并且手册从未记录过它们\xc2\xb2,但不幸的是,包括(GNU shell)在内的许多其他手册仍然不阻止或弃用它们他们。-o[testzshbash

\n
\n

\xc2\xb9 更多信息请参见我对相关 stackoverflow 问答的回答

\n

\xc2\xb2 a test/[内置命令仅在 1991 年的 2.0.3 版本中添加到 zsh 中[[ ... ]]。来自 Korn shell 的特殊构造始终是首选,并且具有自己的语法,其中 and&&用于||andor运算符。

\n

  • @Martian2020,这绝对是个好主意。我建议您通过 bug-bash@gnu.org 向上游提出它 (5认同)

Gil*_*il' 13

Bash 解析[ ! -a WORD ]-a二元运算符,意思是 \xe2\x80\x9cand\xe2\x80\x9d,周围有两个单字测试,如果非空则为 true。因此[ ! -a "" ]为假,如果非空[ ! -a WORD ]则为真。WORD

\n

此解析符合POSIX 规范(尽管严格来说,它不必这样做,因为-aPOSIX 未指定一元)。顺便说一句, mksh 和 zsh 以相同的方式解析这种情况,但 ksh93 使用 unary!后跟 unary 来解析它-a

\n

为了避免歧义,请勿使用已弃用的-a运算符,而应使用标准-e运算符,该运算符没有拼写相同的二元运算符。此外,为了避免较长极端情况下的歧义或错误,请使用&&and||作为二元运算符(外部[ \xe2\x80\xa6 ]或内部[[ \xe2\x80\xa6 ]]),而不是可能存在歧义的-a/ -oinside [ \xe2\x80\xa6 ]

\n