Find 的基于成本的优化器打破了短路评估

Find's cost-based optimiser breaks short-circuit evaluation

引用 find 的手册页(GNU findutils 4.7.0,强调我的):

GNU find searches the directory tree rooted at each given starting-point by evaluating the given expression from left to right, according to the rules of precedence (see section PERATORS), until the outcome is known (the left hand side is false for and operations, true for or), at which point find moves on to the next file name.

因此,当 find 评估 <expr1> -and <expr2> 时,我希望 <expr2> 不会被评估,除非 <expr1> 为真,我依靠它来避免一些错误消息,特别是, 我不希望 find 测试不可读目录是否为空。这是一个 SCCCE:

mkdir some_dir
chmod 333 some_dir
find * -readable ! -empty -printf "yes" -or -printf "no" -prune  

产生

find: ‘some_dir’: Permission denied
no

添加,否则隐式,-and 和括号,由 find 计算的表达式应该 等同于

( ( -readable -and (! -empty ) ) -and -printf "yes" ) -or ( -printf "no" -and -prune )

因此,在意识到some_directory不可读之后,find应该放弃对-printf "yes"的空性测试和求值。相反,它应该跳转到 -printf "no" 的评估,最后是 -prune。输出中的 "Permission denied" 表明它正在评估 -empty 。 (从原始表达式中删除 ! -empty 会使错误消失。)

使用-D tree检查评估树,我看到优化后的形式(为简洁起见在此处编辑)是:

(  (  ( ! -empty ) -and -readable ) -and -printf "yes" ) -or ( -printf "no" -and -prune ) 

据此 -empty 确实被评估,更糟糕的是,在 -readable 之前,这完全搞砸了预期的逻辑。我认为这是一个错误。 我说得对吗?

更新:(2020 年 5 月 26 日)已提交 bug report,开发人员已将其确认为错误。

在我看来,这是 findutils 的 "arm-swapping" 优化中的一个错误,因为它没有考虑到 -empty-xtype 可能会导致 [=12] 的副作用=] 报告错误并以非零状态退出。我 reported 关于 -xtype 的相同问题,findutils 开发人员认为这是一个错误。这个 bug 也很难解决,因为 findutils 没有办法关闭这个优化。 -O0 相当于 -O1 已经应用了它。

如果您需要解决方法,我为 find 编写了一个名为 bfs 的替代品:https://github.com/tavianator/bfs。它完全兼容所有 GNU find 的选项,并且没有这个错误。