为什么是 [[ !!expr ]] 等价于 [[ ! expr ]] 在 bash 中?

vim*_*ene 5 bash shell command-line

在 bash 中,我不明白为什么第三个命令不正确:

[[ 1 -eq 1 ]]         # $? is 0
[[ ! 1 -eq 1 ]]       # $? is 1
[[ ! ! 1 -eq 1 ]]     # $? is 1 (??)
[[ ! ( ! 1 -eq 1 ) ]] # $? is 0
Run Code Online (Sandbox Code Playgroud)

如果我1 -eq 1用任何真表达式替换,并用任何假表达式否定,它似乎会做同样的事情。

Cha*_*ffy 8

[[是一种扩展语法,它提供(主要)一个[. 那么,要了解它的行为,应该从[.

POSIXtest规范描述了[预期的行为方式。在一个地方,它确实提供了符合此问题中描述的期望的描述:

! expression- 如果表达式为假,则为真。如果表达式为真,则为假。

...但后来,关于如何根据原语数量进行解析的更详细描述与此预期相矛盾:

  • 0 个参数:退出假 (1)。
  • 1 个参数:如果 $1 不为空,则退出真 (0);否则,退出假。
  • 2 个参数:如果 $1 是!,如果 $2 为空则退出真,如果 $2 不为空则为假。 如果 $1 是一元主,如果一元测试为真,则退出真,如果一元测试为假,则为假。否则,会产生未指定的结果。
  • 3 个参数:如果 $2 是二进制主,则执行 $1 和 $3 的二进制测试。 如果 $1 是 '!',则否定 $2 和 $3 的两个参数测试。 (过时的 XSI 行为:如果 $1 是 '(' 并且 $3 是 ')',则执行 $2 的一元测试。在不支持 XSI 选项的系统上,如果 $1 是 '(' 并且 $3 是 ',则结果未指定)'。否则,会产生未指定的结果。
  • 4 个参数:如果 $1 是 '!',则否定 $2、$3 和 $4 的三参数测试。 (过时的 XSI 行为:如果 $1 是 '(' 并且 $4 是 ')',则执行 $2 和 $3 的双参数测试。)在不支持 XSI 选项的系统上,如果 $1 是 '(' $4 是')'。否则,结果是不确定的。
  • 超过 4 个参数:结果未指定。

在 的情况下! ! 1 -eq 1,您有一个五参数的情况。结果是 unspecified,因为标准没有指定如果第一个参数是 ,则五参数 case 是四参数 case 的否定!


正如 Zilog80 所建议的:如果您不想受到这些限制,请考虑将您的测试语法! 排除在外! [[ ... ]]发生在 shell 命令解析层而不是定制的测试语法特定逻辑中,并且! ! [[ ... ]]在那里完全有效。

  • @oguzismail,...我想知道我们是否在谈论彼此。我要说的只是行为未指定,这意味着 shell _没有义务_ 将该标志设置为切换,而不是设置并保持设置状态;保持当前的实现与拥有一个基于切换的实现按照OP期望的方式运行一样正确。(当然,未指定也意味着它可以在新版本中切换到以其他方式执行而不破坏任何保证......但是,它也可以切换回来)。 (3认同)

vim*_*ene 3

解析 时!,bash 会为以下表达式设置一个标志,告诉它反转其结果。因此,解析两个或多个!相当于解析单个!. 我提出了一个补丁来解决这个问题,它被接受了。