仅在目录的指定文件名中递归搜索模式/文本?

仅在目录的指定文件名中递归搜索模式/文本?

我有一个目录(例如abc/def/efg),其中包含许多子目录(例如abc/def/efg/(1..300):)。所有这些子目录都有一个公共文件(例如)file.txt。我想仅在其中搜索字符串file.txt而不搜索其他文件。我该怎么做?

我使用过 grep -arin "pattern" *,但是如果我们有许多子目录和文件,它就会非常慢。

答案1

在父目录中,您可以使用findgrep仅对那些文件运行:

find . -type f -iname "file.txt" -exec grep -Hi "pattern" '{}' +

答案2

您也可以使用 globstar。

使用创建grep命令find,如 Zanna 的回答中所述,是一种高度健壮、多功能且可移植的方法(另请参阅sududus 的回答)。 和muru 发布了一个使用选项grep的极好方法--include。但如果您只想使用命令grep和 shell,还有另一种方法可以做到——你(们)能做到外壳本身执行必要的递归

shopt -s globstar   # you can skip this if you already have globstar turned on
grep -H 'pattern' **/file.txt

即使只找到一个匹配的文件,该-H标志也会显示文件名。如果需要,您也可以将、和标志(来自您的示例)传递给。但使用此方法时不要传递或。它是grep-a-i-ngrep-r-R贝壳**递归目录以扩展包含、 和 的glob 模式不是grep

这些指令特定于 Bash shell。Bash 是 Ubuntu(以及大多数其他 GNU/Linux 操作系统)中的默认用户 shell,因此如果您使用的是 Ubuntu 并且不知道您的 shell 是什么,那么它几乎肯定是 Bash。虽然流行的 shell 通常支持目录遍历**glob,但它们的工作方式并不总是相同的。有关更多信息,请参阅斯蒂芬·查泽拉斯很好的答案ls * 、 ls ** 和 ls *** 的结果Unix操作系统

怎么运行的

打开全球星狂欢shell 选项匹配**包含目录分隔符 ( /) 的路径。因此它是一个目录递归 glob。具体来说,man bash解释:

当。。。的时候全球星shell 选项已启用,并且在路径名扩展上下文中使用 *,则用作单个模式的两个相邻 * 将匹配所有文件以及零个或多个目录和子目录。如果后面跟着一个 /,则两个相邻 * 将仅匹配目录和子目录。

您应该对此小心谨慎,因为您可能会运行修改或删除远多于预期文件的命令,尤其是**当您想写的时候却写了*。 (此命令是安全的,它不会更改任何文件。)shopt -u globstar将 globstar shell 选项关闭。

globstar 和 之间存在一些实际差异find

find比 globstar 功能更强大。任何你能用 globstar 做的事情,你都能用这个find命令做。我喜欢 globstar,有时它更方便,但 globstar 不是一个一般的替代find

上述方法不会查找名称以 开头的目录.。有时您不想递归此类文件夹,但有时您想。

与普通的 glob 一样,shell 会构建所有匹配路径的列表,并将它们作为参数传递给命令 ( grep),而不是 glob 本身。如果您调用的文件太多,file.txt以至于生成的命令太长而无法执行,则上述方法将失败。实际上,您需要 (至少) 数千个这样的文件,但这种情况可能会发生。

所使用的方法find不受此限制,因为:

  • 扎娜的方式构建并运行grep可能带有许多路径参数的命令。但是,如果找到的文件多于单个路径中可以列出的文件数,则+-terminated操作将使用部分路径运行该命令,然后使用更多路径再次运行该命令,依此类推。在对多个文件中的字符串进行 ing-exec的情况下,这会产生正确的行为。grep

    与此处介绍的 globstar 方法类似,这将打印所有匹配的行,并在每个行前面添加路径。

  • sududus 的方式grep对每个找到的文件分别运行file.txt。如果文件很多,它可能比其他方法慢,但它确实有效。

    该方法查找文件并打印其路径,然后打印匹配的行(如果有)。这与我的方法生成的格式不同,扎娜的, 和穆鲁

获取颜色find

使用 globstar 的直接好处之一是,在 Ubuntu 上默认grep会产生彩色输出。但是find你也可以轻松获得它

Ubuntu 中的用户帐户是通过别名这让人跑去grep看看。这是grep --color=autoalias grep一件好事别名是只有当你交互发布它们时才会扩展,但这意味着如果你想用该标志find调用,你必须明确地写出它。例如:grep--color

find . -name file.txt -exec grep --color=auto -H 'pattern' {} +

答案3

你不需find要这样做;grep它可以自己完美地处理这个问题:

grep "pattern" . -airn --include="file.txt"

man grep

--exclude=GLOB
      Skip  files  whose  base  name  matches  GLOB  (using   wildcard
      matching).   A  file-name  glob  can  use  *,  ?,  and [...]  as
      wildcards, and \ to quote  a  wildcard  or  backslash  character
      literally.

--exclude-from=FILE
      Skip  files  whose  base name matches any of the file-name globs
      read from FILE  (using  wildcard  matching  as  described  under
      --exclude).

--exclude-dir=DIR
      Exclude  directories  matching  the  pattern  DIR from recursive
      searches.

--include=GLOB
      Search  only  files whose base name matches GLOB (using wildcard
      matching as described under --exclude).

答案4

需要指出的是,如果问题的条件可以采取文学性,则可以直接使用 grep:

grep 'pattern' abc/def/efg/*/file.txt

或者

grep 'pattern' abc/def/efg/{1..300}/file.txt

相关内容