bash 条件表达式中 -a 和 -e 有什么区别?

bash 条件表达式中 -a 和 -e 有什么区别?

man bash

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. [ -a $FILE ]那么和之间有什么区别([ -e $FILE ]如果有的话)?
  2. 如果没有真正的区别,为什么存在两个用于相同目的的标志?

答案1

在 中bash,带有两个参数test命令的上下文,-a file-e file是相同的。但它们有一些区别,因为-a也是二元运算符。

-e一元是由 POSIX 定义的,但-a一元不是。 POSIX 仅定义-a二进制(参见测试POSIX)。

POSIX 定义了三个参数test行为:

3个参数:

  • 如果 $2 是二进制初级,则执行 $1 和 $3 的二进制测试。

  • 如果 $1 是 '!',则否定 $2 和 $3 的双参数测试。

  • 如果$1 是“(”且$3 是“)”,则执行$2 的一元测试。在不支持 XSI 选项的系统上,如果 $1 为“(”且 $3 为“)”,则结果未指定。

  • 否则,产生未指定的结果。

所以-a也会导致奇怪的结果:

$ [ ! -a . ] && echo true
true

-a在三个参数的上下文中被视为二元运算符。看Bash 常见问题解答问题 E1。 POSIX 还提到-a是从 KornShell 获取,但后来更改为,-e因为它混淆了-a二进制和-a一元。

添加主要的 -e 具有与 C shell 提供的功能类似的功能,因为它为 shell 脚本提供了无需尝试打开文件即可查明文件是否存在的唯一方法。由于允许实现添加其他文件类型,因此可移植脚本无法使用:

测试-b foo -o -c foo -o -d foo -o -f foo -o -p foo

查明 foo 是否是现有文件。在历史上的 BSD 系统上,文件是否存在可以通过以下方式确定:

测试-f foo -o -d foo

但没有简单的方法可以确定现有文件是常规文件。早期的提案使用了 KornShell -a 主运算符(具有相同的含义),但后来将其更改为 -e,因为人们担心人们很可能将 -a 主运算符与 -a 二元运算符混淆。

-a二进制文件也被标记为过时的,因为它会导致一些不明确的表达式,其参数超过 4 个。对于这些 >4 个参数表达式,POSIX 定义结果是未指定的。

答案2

.1.那么 [ -a $FILE ] 和 [ -e $FILE ] 之间有什么区别(如果有的话)?

完全没有区别。

在bash 版本505-507中:test.c4.2.45(1)-release

case 'a':           /* file exists in the file system? */
case 'e':
  return (sh_stat (arg, &stat_buf) == 0);

这表明两个标志之间没有真正的区别。

.2.如果没有真正的区别,为什么存在两个用于相同目的的标志?

cuonglm 的回答

答案3

我找到的最好的答案是这个,来自 StackOverflow 的一个问题:

-a已弃用,因此不再在联机帮助页中列出 /usr/bin/test,但仍在 bash 的联机帮助页中列出。使用-e。对于单个“[”,bash 内置函数的行为与 bash 内置函数相同,后者的行为与andtest相同 (一个是另一个的符号链接)。请注意 的效果取决于它的位置:如果它位于开头,则表示。如果它位于两个表达式的中间,则表示逻辑。/usr/bin/[/usr/bin/test-afile existsand

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

对于[[,-a不再用作二进制文件and&&在那里使用),因此它的独特目的是检查那里的文件(尽管已弃用)。所以,否定实际上正如你所期望的那样。

相关内容