什么时候需要多个选项的分组括号?

Pie*_*tru 3 bash find options

我正在使用findgrep命令。

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

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

find $fdir ( -name *.texi -o -name *.org )
Run Code Online (Sandbox Code Playgroud)

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

grep --include "*.texi" --exclude "*.org"
Run Code Online (Sandbox Code Playgroud)

ilk*_*chu 14

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

grep "(" --include "*.texi" --exclude "*.org" ")"
Run Code Online (Sandbox Code Playgroud)

grep会将第一个(视为要搜索的模式,将最后一个)视为文件名。(*)与它们相同foobar而是。因此,您不能将选项分组到grep.


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

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

( patternmatch(filename, "*.texi") || patternmatch(filename, "*.texi") )
Run Code Online (Sandbox Code Playgroud)

比什么都重要。并find为它看到的每个文件评估该表达式。如果你有例如这个:

( -name *.texi -o -name *.org ) -printf something
Run Code Online (Sandbox Code Playgroud)

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

-name *.texi -o -name *.org -printf something
Run Code Online (Sandbox Code Playgroud)

将与

-name *.texi -o -name *.org -a -printf something
Run Code Online (Sandbox Code Playgroud)

因为原子之间有一个隐含的and除非-o给出,然后表达式将是

patternmatch(...) || patternmatch(...) && printf(...)
Run Code Online (Sandbox Code Playgroud)

操作结合较紧密的操作,正好它在几乎所有的编程语言以同样的方式,并以同样的方式乘法的优先级比另外更紧。并且find不知道您想要什么,因为它支持任意表达式。(***)因此,在这种情况下,如果没有括号,它就不会像您想要的那样工作。


正如其他人所指出的,你有命令不需要括号,因为如果没有“行动”( -print-exec在查找表达式等),则默认为打印匹配文件名,也含蓄地把周围的括号表达。

所以,

find "$fdir" -name "*.texi" -o -name "*.org"
Run Code Online (Sandbox Code Playgroud)

表现得像

find "$fdir" \( -name "*.texi" -o -name "*.org" \) -print
Run Code Online (Sandbox Code Playgroud)

但是如果你明确地把它放在-print那里,你还需要明确地把括号放在正确的处理顺序上。请参阅:带有多个 `-name` 和 `-exec` 的 `find` 仅执行 `-name` 的最后匹配项


回到grep:grep不需要括号,也不需要它们,因为它不处理表达式。它没有嵌套的概念,也没有像andor 之类的运算符。相反,它具有硬编码的行为。使用--includeand --exclude,我认为它试图同时满足包含和排除规则。(或者,至少有一个单独的--include规则,而没有一个单独的--exclude规则。)但是对于多个搜索模式,匹配一个另一个就足够了。这两个都是静态规则:你不能给它一个更复杂的表达式来说明哪些模式应该匹配。


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

(** 以同样的方式,它特定于grep第一个非选项参数是一个模式,只有其余的是文件名,或者最后一个参数mv是目的地,而其他参数是要移动的文件,它特定于git它使用任何参数做什么。这些工具做不同的事情,所以他们必须以不同的方式使用命令行参数。)

(*** 有人曾经说过,评估表达式是主要的事情 find。也就是说,它不会找到文件名来打印它们,而是通过文件树来评估它们的表达式。打印和运行外部命令只是副作用。)

  • @Pietru 一些混淆可能与命名相关——`{}` 不是括号,它们是花括号(或方括号)。 (2认同)

Ste*_*itt 7

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

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

find "$fdir" -name '*.texi' -o -name '*.org'
Run Code Online (Sandbox Code Playgroud)

  • @Pietru 从不使用这样未加引号的模式。如果当前目录中有任何与模式匹配的文件,那么在启动 find 之前,shell 会将模式扩展为匹配的文件,因此 find 将永远不会看到该模式,而只会看到它在顶级目录中的扩展。总是引用:`find "$fdir" -name "*.texi" -o -name "*.org" "$@"`。 (3认同)

Adm*_*Bee 6

造成混淆的原因是没有关于程序如何解释命令行参数的标准。通常,参数的解释留给程序员,尽管GNU 编码标准建议程序为此目的使用getopt()getopt_long()函数(来自GNU C 库)。

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

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