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


12

来自man bash

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

只有开发人员才知道#2--除非他们向社区分享他们的推理。
Belmin Fernandez 2014年

Answers:


13

在中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 primary(具有相同的含义),但由于有人担心-a primary与-a二进制运算符混淆的可能性很高,因此将其更改为-e。

-a二进制也被标记为过时的,因为它导致一些模棱两可的表达式,该表达式具有大于4个参数。使用这些> 4参数表达式,POSIX定义的结果是未指定的。


很高兴知道!现在更清楚了:)!
polym

9

.1。那么[-a $ FILE]和[-e $ FILE]之间有什么区别?

完全没有区别。

在线路505-507test.c的bash的版本4.2.45(1)-release

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

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

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

请参阅gnouc的答案。


3
在另一方面,考虑到-a bash中的一种布尔运算符(和),似乎虫容易出现添加此额外的意义,这完全是多余的; 我猜这与与其他实现的兼容性和/或与没有的更早版本的兼容性有关-e
celtschk 2014年

@celtschk- 不是易错的,但是shell的解析器可能是。POSIX为指定的-a-o布尔值[ test ]。但是某些 shell (如bash在区分自变量和运算符时[ test ]很费劲,结果也不可靠。从那时起,POSIX要求任何兼容的Shell都必须在[ test ]括号内至少处理4个参数。
mikeserv

5

我发现的最佳答案是来自StackOverflow问题的答案:

-a已被弃用,因此不再在手册页中列出/usr/bin/test,但仍在bash中列出 。使用-e。对于单个'[',bash内置函数的行为与testbash内置 函数相同,后者的行为与/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&&已在其中使用),因此其唯一目的是在此处检查文件(尽管已弃用)。因此,否定实际上可以达到您的期望。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.