何时需要多个选项的分组括号?

何时需要多个选项的分组括号?

我正在使用findgrep命令。

对于何时使用“或”与标志连接多个选项-o以及使用分组括号以及何时不使用分组括号感到非常困惑。

使用时find,分组括号似乎是必要的

find $fdir ( -name *.texi -o -name *.org )

使用时grep,不使用分组括号

grep --include "*.texi" --exclude "*.org"

答案1

大多数程序,包括grep不专门将括号视为参数。如果你这样做:

grep "(" --include "*.texi" --exclude "*.org" ")"

grep会将第一个(视为要搜索的模式,最后一个)视为文件名。(*)foo就好像它们是一样bar。因此,您无法将选项分组到grep.


但事情是这样的:-name-type-o(不是选项find。它确实需要一些选项,即-P/ -H/ -L,这会影响符号链接处理,但这些不是选项。相反,它们是搜索表达式的一部分,这是特定于find. (**)

强调表达那里。当你给出find表达式时( -name *.texi -o -name *.org ),它更像是类似 C 的表达式

( patternmatch(filename, "*.texi") || patternmatch(filename, "*.texi") )

比其他任何事情都重要。并find为它看到的每个文件评估该表达式。如果你有例如这个:

( -name *.texi -o -name *.org ) -printf something

你需要括号,因为没有它们:

-name *.texi -o -name *.org -printf something

会是一样的

-name *.texi -o -name *.org -a -printf something

因为有一个隐含的除非给出原子之间的关系-o,否则表达式将是

patternmatch(...) || patternmatch(...) && printf(...)

操作比或者运算,与几乎所有编程语言中的运算方式完全相同,并且乘法比加法绑定得更紧密。并且find无法知道你想要什么,因为它支持任意表达式。(***)所以,在这种情况下,如果没有括号,它就不会像你想要的那样工作。


正如其他人指出的,您所拥有的命令不需要括号,因为如果查找表达式中没有“操作”(-print-exec),它默认会打印匹配的文件名,并且还会隐式在表达式两边加上括号。

所以,

find "$fdir" -name "*.texi" -o -name "*.org"

行为就像

find "$fdir" \( -name "*.texi" -o -name "*.org" \) -print

但如果您显式地将 放在-print那里,则还需要显式地放置括号以获得正确的处理顺序。看:具有多个“-name”和“-exec”的“find”仅执行“-name”的最后匹配项


回到grep:grep不带括号,也不需要它们,因为它不处理表达式。它没有嵌套或运算符的概念,例如或者一般来说。相反,它具有硬编码的行为。对于--include--exclude,我认为它试图同时满足包含和排除规则。 (或者,至少有一个单独的--include规则,但没有一个单独的--exclude规则。)但是对于多种搜索模式,匹配一个就足够了,或者其他。这两个都是静态规则:您无法为其提供更复杂的表达式来说明哪些模式应该匹配。


(* GNU grep 会将中间的作为选项,其他实现也可能将它们作为文件名,因为非选项参数之前停止了选项处理。此外,您需要引用或转义括号以防止它们对;这与他们所做的事情无关grep。)

(** 同样,它特定于grep第一个非选项参数是模式,只有其余参数是文件名,或者最后一个参数是mv目标,而其他参数是要移动的文件,并且它特定于git这些工具会执行不同的操作,因此它们必须以不同的方式使用命令行参数。)

(*** 有人曾经说过,求值表达式是主要的事 find做。也就是说,它没有找到要打印的文件名,而是通过文件树来查找计算表达式在他们。打印和运行外部命令只是一个副作用。)

答案2

没有一般规则:给定命令将哪些内容识别为参数取决于该命令。grep不使用括号对参数进行分组。

为了find, 仅当优先级为相对或者需要被覆盖;这类似于数学中括号的使用。在您的示例中,不需要它们,因为默认优先级赋予表达式相同的整体含义:

find "$fdir" -name '*.texi' -o -name '*.org'

答案3

造成混乱的原因是程序如何解释命令行参数没有标准。一般来说,参数的解释留给程序员,尽管GNU编码标准建议程序使用getopt()getopt_long()函数(来自GNU C 库) 为了这个目的。

这意味着定义运算符优先级的括号的解释是 的函数find,而不是用于调用 的 shell 的函数find。 “简单”的程序员grep没有以这种方式实现他们的选项解析算法,所以grep一开始就不会理解这个符号。

但请注意括号在 shell 中具有特殊含义:它们表示所包含的内容是要运行的命令在子外壳中。因此,您发布的命令实际上应该不起作用;正如 @terdon 所提到的,您必须转义括号(如\( ... \))才能让 shellfind首先将它们传递给它们。

答案4

我认为该手册对如何find使用括号有一些见解可以帮助您:

2.12 将原色与运算符相结合

运算符根据测试和操作构建复杂的表达式。运算符按优先级降序排列:

( expr )

强制优先。如果expr为真则为真。

! expr
-not expr

如果为假则为真expr。在某些 shell 中,有必要保护 '!'通过引用它来从 shell 解释中获得。

expr1 expr2 expr1 -a
expr2 expr1 -and expr2

和;如果为 false,expr2则不进行评估。expr1

expr1 -o expr2 expr1 -or expr2

或者;如果为 true,expr2则不进行评估。expr1

expr1 , expr2

列表;两者expr1expr2总是被评估。如果expr2为真则为真。的值expr1被丢弃。该运算符允许您在一次遍历中执行多个独立操作,而不依赖于其他操作是否成功。这两个操作expr1并不expr2 总是完全独立的,因为expr1可能会产生副作用,例如触摸或删除文件,或者可能使用-prune’ which would also affectexpr2`。

find根据优先级规则,通过从左到右评估表达式来搜索以每个文件名为根的目录树,直到知道结果(左侧对于 为假-and,对于 为真-or),此时 find 继续进行下一个文件名。

相关内容