我正在使用find
和grep
命令。
当多个选项由“或”与-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
会将第一个(
视为要搜索的模式,将最后一个)
视为文件名。(*)与它们相同foo
,bar
而是。因此,您不能将选项分组到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
不需要括号,也不需要它们,因为它不处理表达式。它没有嵌套的概念,也没有像and和or 之类的运算符。相反,它具有硬编码的行为。使用--include
and --exclude
,我认为它试图同时满足包含和排除规则。(或者,至少有一个单独的--include
规则,而没有一个单独的--exclude
规则。)但是对于多个搜索模式,匹配一个或另一个就足够了。这两个都是静态规则:你不能给它一个更复杂的表达式来说明哪些模式应该匹配。
(* GNU grep 会将中间的作为选项,其他实现也可能将它们作为文件名,因为之前的非选项参数停止了选项处理。此外,您需要引用或转义括号以防止它们对shell具有特殊意义; 这与如何grep
处理它们无关。)
(** 以同样的方式,它特定于grep
第一个非选项参数是一个模式,只有其余的是文件名,或者最后一个参数mv
是目的地,而其他参数是要移动的文件,它特定于git
它使用任何参数做什么。这些工具做不同的事情,所以他们必须以不同的方式使用命令行参数。)
(*** 有人曾经说过,评估表达式是主要的事情 find
。也就是说,它不会找到文件名来打印它们,而是通过文件树来评估它们的表达式。打印和运行外部命令只是副作用。)
没有一般规则:给定命令识别为参数的内容取决于命令。grep
不使用括号对参数进行分组。
对于find
,只有当and vs或的优先级需要被覆盖时才需要括号;这类似于数学中括号的使用。在您的示例中,它们不是必需的,因为默认优先级赋予表达式相同的整体含义:
find "$fdir" -name '*.texi' -o -name '*.org'
Run Code Online (Sandbox Code Playgroud)
造成混淆的原因是没有关于程序如何解释命令行参数的标准。通常,参数的解释留给程序员,尽管GNU 编码标准建议程序为此目的使用getopt()
和getopt_long()
函数(来自GNU C 库)。
这意味着定义运算符优先级的括号的解释是 的函数find
,而不是用于调用的 shell的函数find
。grep
“简单”的程序员没有以这种方式实现他们的选项解析算法,所以grep
首先不会理解这个符号。
但是请注意,括号在 shell 中具有特殊含义:它们表示包含的内容是要在子 shell 中运行的命令。因此,您发布的命令实际上应该不起作用;正如@terdon 所提到的,您必须转义括号(如\( ... \)
),以便让外壳首先将它们传递给find
。