为什么 GNU find 的“-or”标志会导致我的表达式以意外的方式求值?

为什么 GNU find 的“-or”标志会导致我的表达式以意外的方式求值?

以下内容按预期工作:

[pitserver ~]% sudo find /home/pitserver/operator -uid 11 -exec ls -nld {} +
drwxr-xr-x 2 11 28 4096 Jan 30  2006 /home/pitserver/operator
-rw------- 1 11 28   32 Oct  3  2005 /home/pitserver/operator/.amandahosts
-rw------- 1 11 28  700 Jan 30  2006 /home/pitserver/operator/.viminfo
-rw------- 1 11 28   65 Jan 30  2006 /home/pitserver/operator/.Xauthority

我希望以下列出每个文件,但它列出了每个文件除了 .amandahosts:

[pitserver ~]% sudo find /home/pitserver/operator -name '.amandahosts' -or -uid 11 -exec ls -nld {} +        
drwxr-xr-x 2 11 28 4096 Jan 30  2006 /home/pitserver/operator
-rw------- 1 11 28  700 Jan 30  2006 /home/pitserver/operator/.viminfo
-rw------- 1 11 28   65 Jan 30  2006 /home/pitserver/operator/.Xauthority

为什么会这样呢?

答案1

根据man find、并置(这是隐含的“and”运算符)优先于-or运算符,因此人们可能期望参数的计算方式如下:

-name '.amandahosts' -or -uid 11) 和 (-exec ls -ld {} +

事实上,如果我将括号添加到 find 命令中,它会按预期工作:

[pitserver ~]% sudo find /home/pitserver/operator '(' -name '.amandahosts' -or -uid 11 ')' -exec ls -nld {} +
drwxr-xr-x 2 11 28 4096 Jan 30  2006 /home/pitserver/operator
-rw------- 1 11 28   32 Oct  3  2005 /home/pitserver/operator/.amandahosts
-rw------- 1 11 28  700 Jan 30  2006 /home/pitserver/operator/.viminfo
-rw------- 1 11 28   65 Jan 30  2006 /home/pitserver/operator/.Xauthority

然而, find 实际上是这样解释参数的:

-name '.amandahosts') 或者 (-uid 11 -exec ls -ld {} +

正如你在这里看到的:

[pitserver ~]% sudo find /home/pitserver/operator -name '.amandahosts' -or '(' -uid 11 -exec ls -nld {} + ')'
drwxr-xr-x 2 11 28 4096 Jan 30  2006 /home/pitserver/operator
-rw------- 1 11 28  700 Jan 30  2006 /home/pitserver/operator/.viminfo
-rw------- 1 11 28   65 Jan 30  2006 /home/pitserver/operator/.Xauthority

这里发生的情况是“或”短路了。-uid 11 -exec ls -ld {} +评估“-or”( ) 的第二部分除非第一部分 ( -name '.amandahosts') 的计算结果为错误的。因此 find 仅-exec ...当文件未命名时才会运行'.amandahosts'。了解其工作原理的一种方法是观察以下内容是否成功:

[pitserver ~]% sudo find /home/pitserver/operator -name '.amandahosts' -exec ls -nld {} + -or -uid 11 -exec ls -nld {} +
-rw------- 1 11 28 32 Oct  3  2005 /home/pitserver/operator/.amandahosts
drwxr-xr-x 2 11 28 4096 Jan 30  2006 /home/pitserver/operator
-rw------- 1 11 28  700 Jan 30  2006 /home/pitserver/operator/.viminfo
-rw------- 1 11 28   65 Jan 30  2006 /home/pitserver/operator/.Xauthority

解决此问题的最佳方法似乎是在使用“或”运算符时始终使用括号,因为这恰好给出了所需的行为:

'(' -name '.amandahosts' -or -uid 11 ')' -exec ls -nld {} +

相关内容