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


16

我有一个abc/def/efg包含许多子目录(例如:)的目录(例如,abc/def/efg/(1..300))。所有这些子目录都有一个公共文件(例如file.txt)。我只想在此字符串中搜索file.txt其他文件。我怎样才能做到这一点?

我曾经用过 grep -arin "pattern" *,但是如果我们有很多子目录和文件,那将非常慢。


Answers:


21

在父目录中,您可以使用find然后grep仅在这些文件上运行:

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

2
我建议也传递-H给,grep以便在仅传递一个路径的情况下,仍然打印该路径(而不是仅从文件中匹配的行)。
伊利亚·卡根

24

您也可以使用globstar。

就像Zanna的答案中那样,grep使用构建命令find是一种高度健壮,多功能且可移植的方式(请参见sudodus的答案)。而且,muru发布了使用grep--include选项的出色方法。但是,如果只想使用grep命令和外壳程序,则还有另一种方法可以使外壳程序本身执行必要的递归

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

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

这些说明特定于Bash shell。Bash是Ubuntu(以及大多数其他GNU / Linux操作系统)中的默认用户外壳程序,因此,如果您在Ubuntu上并且不知道外壳程序是什么,则几乎可以肯定是Bash。尽管流行的shell通常支持目录遍历**glob,但是它们并不总是以相同的方式工作。欲了解更多信息,请参阅斯特凡Chazelas出色答卷,以LS的结果*,LS **和*** LSUnix.SE

怎么运行的

启用globstar bash shell选项将使**匹配路径包含目录分隔符(/)。因此,它是目录递归的glob。具体来说,如下所述man bash

globstar壳选项被启用,并且*是在路径扩展上下文中使用的,两个相邻* S用作单一模式将匹配的所有文件和零个或多个目录和子目录。如果后跟一个/,则两个相邻的* s仅匹配目录和子目录。

您应该对此小心谨慎,因为您可以运行用于修改或删除远远超出预期数量的文件的命令,尤其是如果您**在打算编写时编写文件时*。(此命令很安全,不会更改任何文件。)shopt -u globstar关闭globstar shell选项。

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

find比globstar用途更广泛。您可以使用globstar进行任何操作,也可以使用该find命令进行操作。我喜欢globstar,有时更方便,但是globstar并不是的通用替代品find

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

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

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

  • Zanna的方式可以构建和运行grep可能包含许多路径参数的命令。但是,如果发现的文件数量超出单个路径中列出的文件数量,则+-terminated -exec操作将使用某些路径运行命令,然后使用更多路径再次运行该命令,依此类推。在grep多个文件中输入一个字符串的情况下,这将产生正确的行为。

    就像这里介绍的globstar方法一样,它会打印所有匹配的行,并在每行之前添加路径。

  • sudodus的方法grep针对每个file.txt发现分别运行。如果文件很多,它可能会比其他方法慢一些,但是可以。

    该方法查找文件并打印它们的路径,然后匹配行(如果有)。这是与我的方法Zannamuru产生的格式不同的输出格式。

变色 find

使用globstar的直接好处之一是,默认情况下在Ubuntu grep上将产生彩色输出。但是,您可以轻松地得到这个find,太

在Ubuntu中创建用户帐户时使用的别名将使其grep真正运行grep --color=auto(运行alias grep以查看)。这是一件好事,是别名几乎只有当你发给他们交互式扩展,但它意味着,如果你想find调用grep--color标志,你就必须把它明确写入。例如:

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

您可能需要更清楚地声明需要使用bash外壳程序才能正常工作。您确实在“ globstar bash shell选项”中暗含了它,但是阅读速度太快的人们很容易错过它。
Stig Hemmer

我删除了答案,因为它引起了很多批评。因此,您应该在答案中删除对其的引用。
sudodus

@StigHemmer谢谢-我已经澄清了并不是所有的shell都具有此功能。尽管许多shell(不仅是bash)都支持目录遍历**glob,但您的核心批判是正确的:**此答案中的呈现特定于bash,shopt仅是bash,术语 “ globstar”是(我认为)bash和仅tcsh。我本来是因为这些复杂性而忽略了这一点,但是您是对的,这有点令人困惑。我没有在这个答案中进行详尽的讨论,而是链接到另一篇(很详尽的)文章,它很繁重。
伊莱亚·卡根

@sudodus我已经这样做了,但是我希望这是暂时的。我和其他人发现您的答案很有价值。确实-e不应该将其应用于路径,但这很容易解决。对于第一个命令,只需省略-e。对于第二个,使用find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;。用户有时会偏爱您的方式(-e固定用法),而另一种方式是每条匹配行打印一条路径;您的文件会在找到的每个文件中打印一个路径,然后显示grep结果。
伊莱亚·卡根

@sudodus所以grep它本身不会做你在做什么。其他一些批评也是错误的。如果没有(或)grep -H-exec则不会变色。IEEE 1003.1-2008不能保证可以扩展,但是Ubuntu可以找到GNU查找如果您还可以,我将编辑您的帖子以修复该错误(并澄清其用例),您可以查看是否要删除。(我的代表可以查看/编辑已删除的帖子。)--colorGREP_COLOR{}##### {}:-e
Eliah Kagan

18

您不需要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).

很好-这似乎是最好的方法。简单高效。我希望我已经知道(或想查看此手册)。谢谢!
伊利亚·卡根

@EliahKagan我更惊讶Zanna没有发布此消息-一段时间前,我已经为另一个答案显示了此选项的示例。:)
muru

2
缓慢的学习者,a,但我最终到了那里,您的教导并没有完全浪费在我身上;)
Zanna

这是非常简单且容易记住的。谢谢。
Rajesh Keladimath '17

我同意,这是最好的答案。我应该删除答案以减少混乱,还是让它停留以表明还有其他选择,以及find?
该如何做

8

muru的答案中给出的方法(使用grep带有--include指定文件名的标志运行)通常是最佳选择。但是,也可以使用完成此操作find

此答案中的方法用于为找到的每个文件单独find运行grep,并在每个文件中找到的匹配行上方,仅一次打印每个文件的路径。(其他答案中涵盖了在每条匹配行的前面打印路径的方法。)


您可以将目录更改为拥有这些文件的目录树的顶部。然后运行:

find . -name "file.txt" -type f -exec echo "##### {}:" \; -exec grep -i "pattern" {} \;

该命令将打印.每个名为的文件的路径(相对于当前目录,包括文件名本身)file.txt,然后打印该文件中所有匹配的行。这是有效的,因为它{}是找到的文件的占位符。每个文件的路径都以前缀为前缀#####,从而与其内容分开,并且在该文件的匹配行之前仅打印一次。(file.txt不包含任何匹配项的被调用文件仍会打印其路径。)与在每条匹配行的开头打印路径的方法所获得的输出相比,您可能会发现此输出的混乱程度更低。

这样的使用find几乎总是比grep每个文件(grep -arin "pattern" *)上运行更快,因为find搜索名称正确的文件并跳过所有其他文件。

Ubuntu使用GNU find即使它出现在较大的字符串(如)中,它也会一直扩展{}##### {}:。如果您需要命令来工作,find对系统可能不支持这种,或者你更喜欢使用-exec只有在绝对必要的行动,你可以使用:

find . -name "file.txt" -type f -printf '##### %p:\n' -exec grep -i "pattern" {} \;

为了使输出更易于阅读,可以使用ANSI转义序列来获取彩色文件名。这使得每个文件的路径标题与在其下打印的匹配行相比更加突出:

find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;

会导致你的shell换码绿色成在终端生产绿色环保的实际转义序列,并做同样的事情与正常颜色换码。这些转义被传递给find,当它打印文件名时会使用它们。($' '此处必须使用引号,因为find-printf动作无法识别\eANSI转义码。)

如果你愿意,你也可以使用-exec系统的printf命令(其中不支持\e)。因此,做同一件事的另一种方法是:

find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;

我打算用数组创建“ for循环”,但我没有考虑过find的exec native选项。好一个!但是我认为使用dot会将您定位在您已经所在的目录中。如果我错了,请纠正我。以查找顺序指定直接解析的更好吗?find abc/def/efg -name "file.txt" -type f -exec echo -e "##### {}:" \; -exec grep -i "pattern" {} \;
kcdtv

当然,这将消除cd abc/def/efg'change directory'命令:-)
sudodus

(1)为什么要指定-e选项echo?这将导致它处理任何包含反斜杠的文件名。(2)不能保证将其{}用作参数的一部分。说-exec echo "#####" {} \;还是会更好-exec printf "##### %s:\n" {} \;。(3)为什么不只是使用-print-printf?(4)也考虑grep -H
G-Man说'Resstate Monica''01

@ G-man,1)因为我最初使用的是ANSI颜色:find . -name "file.txt" -type f -exec echo -e "\0033[32m{}:\0033[0m" \; -exec grep -i "pattern" {} \;2)您可能是对的,但到目前为止,这对我来说是可行的。3)-print和-printf也是替代方案。4)这已经在主要答案中了。-无论如何,我们欢迎您回答:-)
sudodus

您不需要两个-exec电话。只需使用grep -H,即可打印文件名(彩色)以及匹配的文本。
terdon

0

只是指出,如果可以将问题的条件应用于文学,则可以使用直接grep:

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

要么

grep 'pattern' abc/def/efg/{1..300}/file.txt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.