如何递归地gresing所有目录和子目录?

How do I recursively grep all directories and subdirectories?

提问人:wpiri 提问时间:1/1/2010 最后编辑:Geoffrey Halewpiri 更新时间:10/11/2023 访问量:2195118

问:

如何递归所有目录和子目录?grep

find . | xargs grep "texthere" *
Linux Unix GREP

评论

141赞 Frank Schmitt 10/25/2013
@TC1 可悲的是,grep 本身可以回答这个问题(至少是 GNU grep):grep --help |grep 递归
12赞 Nick McCurdy 10/26/2013
如果你发现自己经常使用 grep 进行递归搜索(特别是如果你手动做大量的文件/目录排除),你可能会发现 ack(一个非常对程序员友好的 grep 替代品)很有用。
26赞 Ben 1/9/2014
实际上,-r 和 --recursive 都没有在我工作时使用的 Solaris 盒子上工作。grep 的手册页没有提到任何递归内容。我不得不求助于自己寻找和 xargs。
9赞 dranxo 5/22/2014
AG 是我现在最喜欢的方式 github.com/ggreer/the_silver_searcher
2赞 Bulrush 9/16/2015
grep -rin xlsx *.pl在 Redhat Linux 上对我不起作用。我收到“不匹配”错误。

答:

3095赞 Vinko Vrsalovic 1/1/2010 #1
grep -r "texthere" .

第一个参数表示要搜索的正则表达式,而第二个参数表示应搜索的目录。在本例中,表示当前目录。.

注意:这适用于 GNU grep,在某些平台上,如 Solaris,您必须专门使用 GNU grep,而不是传统实现。对于 Solaris,这是命令。ggrep

评论

46赞 Withheld 2/1/2013
注意:“grep -r”仅适用于较新的 grep。例如,它不适用于随附的 grep。AIX 5.3
139赞 Eloff 4/6/2013
使用 grep -R 跟踪符号链接。
72赞 Sadegh 1/23/2015
很高兴知道“-i”会使其不区分大小写,并且“-n”还包括每个匹配结果的行号。
41赞 Jeff 5/7/2015
同样值得一提的是,如果您只是在寻找固定字符串而不是正则表达式,请使用 -F 选项。它将通过不调用正则表达式解析器来节省大量时间。如果您正在搜索大量文件,则非常方便。
7赞 totten 3/22/2016
别名 rgrep='grep -r'
141赞 user31056 1/1/2010 #2

也:

find ./ -type f -print0 | xargs -0 grep "foo"

但这是一个更好的答案。grep -r

评论

15赞 Edd Steel 1/1/2012
或者,如果您不想担心文件名中的空格,则在支持的情况下效果很好。find . -type f -exec grep "foo" '{}' \;
5赞 Jeff 4/20/2013
如果您打算通过 xargs 将 find 管道传递给 grep,并且如果您只搜索固定字符串(即,不是正则表达式),您可能会从调用 grep -F 选项中受益,因此 grep 不会为每次调用加载正则表达式引擎。如果有很多文件,它会快得多。
3赞 Wes 8/27/2013
找到。-type f -exec grep -胡 “foo” {} \;是我使用它,因为它给出了文件名。
1赞 Ciro Santilli OurBigBook.com 2/16/2014
这适用于所有 *nix,因为它是 POSIX 7
3赞 aehlke 7/3/2014
find ./ -type f -print0 | xargs -0 grep "foo"
859赞 christangrant 12/31/2011 #3

如果您知道所需文件的扩展名或模式,另一种方法是使用选项:--include

grep -r --include "*.txt" texthere .

您还可以使用 提及要排除的文件。--exclude

如果您经常搜索代码,Ag(The Silver Searcher)是 grep 的更快替代品,grep 是为搜索代码而定制的。例如,它默认是递归的,并自动忽略 中列出的文件和目录,因此您不必继续传递同样繁琐的排除选项来 grep 或 find。.gitignore

评论

3赞 Withheld 2/1/2013
与Linux和Cygwin附带的grep配合得很好,但与AIX附带的grep不一样。
1赞 Dan Dascalescu 2/19/2014
@KrzysztofWolny: ' ' 而不是在 Ubuntu 上运行良好。PS:这应该是一个反引空间,但 SO markdown 解析器失败了。=
7赞 Bernhard 5/15/2014
@DanDascalescu 我投了赞成票,而不是 Ag,只是为了让你知道:)grep
2赞 Tom Taylor 9/24/2017
我们是否可以选择在递归搜索时排除目录?
1赞 Bob Stein 2/20/2019
Windows cygwin 喜欢双引号--include "*.txt" --include "*.TXT"
12赞 chim 12/4/2012 #4

只是文件名也很有用

grep -r -l "foo" .
165赞 VonC 2/14/2013 #5

我现在总是使用(即使在带有 GoW 的 Windows 上 -- Windows 上的 Gnu):

grep --include="*.xxx" -nRHI "my Text to grep" *

(正如 kronen 在评论中指出的那样,您可以添加 void 权限被拒绝的输出)2>/dev/null

这包括以下选项:

--include=PATTERN

在仅搜索文件匹配的目录中递归。PATTERN

-n, --line-number

在每行输出前加上其输入文件中的行号。

(注意:phuclv 在评论中补充说 -n 会大大降低性能,因此您可能想跳过该选项)

-R, -r, --recursive

以递归方式读取每个目录下的所有文件;这等同于选项。-d recurse

-H, --with-filename

打印每个匹配项的文件名。

-I     

处理二进制文件,就好像它不包含匹配的数据一样;
这等同于选项。
--binary-files=without-match

如果我想要不区分大小写的结果,我可以添加“”()。i-nRHIi

我可以得到:

/home/vonc/gitpoc/passenger/gitlist/github #grep --include="*.php" -nRHI "hidden" *
src/GitList/Application.php:43:            'git.hidden'      => $config->get('git', 'hidden') ? $config->get('git', 'hidden') : array(),
src/GitList/Provider/GitServiceProvider.php:21:            $options['hidden'] = $app['git.hidden'];
tests/InterfaceTest.php:32:        $options['hidden'] = array(self::$tmpdir . '/hiddenrepo');
vendor/klaussilveira/gitter/lib/Gitter/Client.php:20:    protected $hidden;
vendor/klaussilveira/gitter/lib/Gitter/Client.php:170:     * Get hidden repository list
vendor/klaussilveira/gitter/lib/Gitter/Client.php:176:        return $this->hidden;
...

评论

1赞 Radim Cernej 1/23/2016
Gow 看起来很有前途 - 比我一直在使用的 GNU Windows 实用程序更新。现在试试...
3赞 lorniper 8/4/2016
这里最后一个字符*是什么意思?
3赞 VonC 8/4/2016
@lorniper它使 shell 选择当前目录中的所有文件和文件夹,从而使 grep 应用于这些文件,并(由于该选项而递归地)应用于文件夹。-R
3赞 VonC 8/4/2016
@lorniper Noy exactly : or is a glob pattern(由 shell 解释): unix.stackexchange.com/a/64695/7490.'' 将选择 dotfiles 或 dot 文件夹(如*...git/)
1赞 phuclv 2/3/2019
以前我一直在使用,但后来我了解到 -n 会大大降低性能,所以我只是在真正需要的时候使用它,通常我会使用grep -rnI-rI
28赞 rook 8/8/2013 #6

在 POSIX 系统中,您找不到参数 for,并且不会运行,但如果您使用命令,它将:-rgrepgrep -rn "stuff" .find

find . -type f -exec grep -n "stuff" {} \; -print

同意 和 。SolarisHP-UX

评论

2赞 user1169587 4/27/2016
{} \是什么意思;-分别打印?
5赞 rook 4/27/2016
在选项中 - 符号是对当前由工具找到的文件名的引用(即对我们找到的文件名执行某些操作),选项也应该以符号结尾(以标记 exec 命令的结尾),但由于这一切都在 shell 中运行,因此该符号应该被转义。最后,选项允许工具在屏幕上打印出找到的文件名。-exec{}find-exec;-printfind
7赞 sumit kumar 12/19/2013 #7

这应该有效:

grep -R "texthere" *
2赞 m.thome 5/22/2014 #8

请注意,当 find 匹配的文件太多时,各种解决方案将遇到“参数列表到长”错误。find . -type f | xargs grep whatever

最好的办法是,但如果不可用,请改用。grep -rfind . -type f -exec grep -H whatever {} \;

评论

1赞 tripleee 4/21/2015
哼? 是专门针对“参数列表太长”问题的解决方法。xargs
3赞 m.thome 4/23/2015
好吧,不 - xargs 专门用于将参数管道转换为参数列表,但是是的,当与 -s 和/或 -L 一起使用时,现代 xargs 确实可以通过分解多个命令调用来处理非常长的参数列表,但它默认不是这样配置的(并且在上述任何响应中都没有)。举个例子:find . -type f | xargs -L 100 grep whatever
1赞 tripleee 4/23/2015
那会在哪个平台上?POSIX xargs 是标准化的,具有开箱即用的此行为。xargs 实用程序应限制命令行长度,以便在调用命令行时,组合参数和环境列表......不得超过 {ARG_MAX}-2048 字节。
1赞 m.thome 4/25/2015
嗯。虽然 gnu 文档在这个基础上不如 posix 清晰,而且我不再有权访问导致我做出此声明的机器,但我无法确认我对任何当前实现的原始解释。当然,如果可用,递归 grep 仍然是可取的,但没有理由避免使用 xargs 配方(不过,请对 grep 使用 -H 以避免 grep 的最终调用只传递一个文件名)。
10赞 dranxo 5/22/2014 #9

AG 是我现在最喜欢的方式 github.com/ggreer/the_silver_searcher。它基本上与 ack 相同,但进行了更多优化。

这是一个简短的基准。我在每次测试前清除缓存(参见 https://askubuntu.com/questions/155768/how-do-i-clean-or-disable-the-memory-cache )

ryan@3G08$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time grep -r "hey ya" .

real    0m9.458s
user    0m0.368s
sys 0m3.788s
ryan@3G08:$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time ack-grep "hey ya" .

real    0m6.296s
user    0m0.716s
sys 0m1.056s
ryan@3G08$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time ag "hey ya" .

real    0m5.641s
user    0m0.356s
sys 0m3.444s
ryan@3G08$ time ag "hey ya" . #test without first clearing cache

real    0m0.154s
user    0m0.224s
sys 0m0.172s
4赞 user3606336 7/9/2015 #10

在我的 IBM AIX Server(操作系统版本:AIX 5.2)中,使用:

find ./ -type f -print -exec grep -n -i "stringYouWannaFind" {} \; 

这将打印出文件中的路径/文件名和相对行号,如下所示:

./inc/xxxx_x.h

2865: /** 描述 : stringYouWannaFind */

无论如何,它对我有用:)

1赞 PJ Brunet 8/13/2015 #11

只是为了好玩,如果@christangrant答案太多而无法输入,可以快速而肮脏地搜索 *.txt 个文件 :-)

grep -r texthere .|grep .txt

7赞 fedorqui 12/1/2015 #12

如果要从目录结构中查找所有文件中的特定内容,则可以使用,因为它更清楚您正在做什么:find

find -type f -exec grep -l "texthere" {} +

请注意,(L 的小写字母)显示包含文本的文件的名称。如果您想要打印匹配项本身,请将其删除。或者用于将文件与匹配项一起获取。总而言之,其他替代方案是:-l-H

find -type f -exec grep -Hn "texthere" {} +

其中打印行号。-n

评论

3赞 ShadowRanger 1/30/2016
被点赞为唯一既能避免不必要的使用又能避免使用而不是使用的解决方案,从而避免了大量不必要的流程启动。:-)findxargs+\;-exec
12赞 Girdhar Singh Rathore 1/29/2016 #13

以递归方式查找包含以下特定用途的命令的名称 为:filespathstringUNIX

find . | xargs grep "searched-string"

为:Linux

grep -r "searched-string" .

在服务器上查找文件UNIX

find . -type f -name file_name

在 LINUX 服务器上查找文件

find . -name file_name
6赞 Geoffrey Hale 2/13/2016 #14

grep -r "texthere" . (期末通知期)

(^信用:https://stackoverflow.com/a/1987928/1438029)


澄清:

grep -r "texthere" /(递归 grep 所有目录和子目录)

grep -r "texthere" .(递归地 grep 这些目录和子目录)

grep 递归

grep [options] PATTERN [FILE...]

[选项]

-R, -r, --recursive

以递归方式读取每个目录下的所有文件。

这等效于 or 选项。-d recurse--directories=recurse

http://linuxcommand.org/man_pages/grep1.html

grep 帮助

$ grep --help

$ grep --help |grep recursive
  -r, --recursive           like --directories=recurse
  -R, --dereference-recursive

选择

ack (http://beyondgrep.com/)

ag (http://github.com/ggreer/the_silver_searcher)

5赞 Girdhar Singh Rathore 3/8/2016 #15

下面是用于递归搜索 on 和 environment 的命令。StringUnixLinux

对于命令是:UNIX

find . -name "string to be searched" -exec grep "text" "{}" \;

对于命令是:Linux

grep -r "string to be searched" .

评论

1赞 tripleee 10/26/2022
使用 with 需要更多的赞成票,而不是具有不可移植性和(略微)效率较低的众多答案find-exec-print0 | xargs -0
7赞 arkod 4/7/2016 #16

这是我当前机器上适用于我的情况(Windows 7 上的 git bash):

find ./ -type f -iname "*.cs" -print0 | xargs -0 grep "content pattern"

我总是忘记带有空格的路径的 -print0 和 -0。

编辑:我的首选工具现在是ripgrep:https://github.com/BurntSushi/ripgrep/releases。它的速度非常快,并且具有更好的默认值(例如默认的递归)。与我的原始答案相同的示例,但使用 ripgrep:rg -g "*.cs" "content pattern"

14赞 SarcasticSully 8/4/2016 #17

如果您只想关注实际目录,而不是符号链接,

grep -r "thingToBeFound" directory

如果你想遵循符号链接和实际目录(注意无限递归),

grep -R "thing to be found" directory

由于您尝试以递归方式进行 grep,因此以下选项也可能对您有用:

-H: outputs the filename with the line

-n: outputs the line number in the file

因此,如果您想在当前目录或任何子目录中找到包含 Darth Vader 的所有文件并捕获文件名和行号,但不希望递归遵循符号链接,则该命令将是

grep -rnH "Darth Vader" .

如果您想在目录中找到所有提及的单词 cat

/home/adam/Desktop/TomAndJerry 

并且您当前位于目录中

/home/adam/Desktop/WorldDominationPlot

并且您想要捕获字符串“cats”的任何实例的文件名而不是行号,并且您希望递归遵循符号链接(如果找到它们),您可以运行以下任一命令

grep -RH "cats" ../TomAndJerry                   #relative directory

grep -RH "cats" /home/adam/Desktop/TomAndJerry   #absolute directory

源:

运行“grep --help”

符号链接的简短介绍,对于任何阅读此答案并对我引用它们感到困惑的人:https://www.nixtutor.com/freebsd/understanding-symbolic-links/

评论

0赞 semtex41 3/9/2020
很好的答案。额外的开关 (-rnh) 非常有帮助,所以感谢您的建议。
2赞 Victor Faria 10/4/2016 #18

我想这就是你想写的

grep myText $(find .)

如果您想找到 grep 命中的文件,这可能是其他有用的东西

grep myText $(find .) | cut -d : -f 1 | sort | uniq

评论

1赞 Yu Shen 11/16/2016
它非常直观:例如:grep -i acc $(find . -name “execution*.*”)
1赞 tripleee 10/26/2022
这遇到了几个常见的初学者问题,例如带有空格的文件名等。请参阅 mywiki.wooledge.org/BashFAQ/020iki.fi/era/unix/award.html#backticks
2赞 James Brown 6/9/2017 #19

下面是一个递归函数(使用 bash 和 sh 进行轻微测试),该函数遍历给定文件夹的所有子文件夹 ($1) 并使用搜索给定文件中的给定字符串 ($3) ($2):grep

$ cat script.sh
#!/bin/sh

cd "$1"

loop () {
    for i in *
    do
        if [ -d "$i" ]
        then
            # echo entering "$i"
            cd "$i"
            loop "$1" "$2"
        fi
    done

    if [ -f "$1" ]
    then
        grep -l "$2" "$PWD/$1"
    fi

    cd ..
}

loop "$2" "$3"

运行它和示例输出:

$ sh script start_folder filename search_string
/home/james/start_folder/dir2/filename
3赞 JSON C11 10/1/2017 #20

有关可用标志的列表:

grep --help 

返回当前目录中正则表达式 texthere 的所有匹配项,并具有相应的行号:

grep -rn "texthere" .

返回 texthere 的所有匹配项,从根目录开始,具有相应的行号并忽略大小写:

grep -rni "texthere" /

此处使用的标志:

  • -r递归的
  • -n打印带输出的行号
  • -i忽略大小写
5赞 hughdbrown 1/10/2018 #21

在2018年,您想使用OR因为它们比替代品快得多。ripgrepthe-silver-searcher

下面是一个包含 336 个一级子目录的目录:

% find . -maxdepth 1 -type d | wc -l
     336

% time rg -w aggs -g '*.py'
...
rg -w aggs -g '*.py'  1.24s user 2.23s system 283% cpu 1.222 total

% time ag -w aggs -G '.*py$'
...
ag -w aggs -G '.*py$'  2.71s user 1.55s system 116% cpu 3.651 total

% time find ./ -type f -name '*.py' | xargs grep -w aggs
...
find ./ -type f -name '*.py'  1.34s user 5.68s system 32% cpu 21.329 total
xargs grep -w aggs  6.65s user 0.49s system 32% cpu 22.164 total

在 OSX 上,这将安装: 。这将安装: 。ripgrepbrew install ripgrepsilver-searcherbrew install the_silver_searcher

评论

3赞 tripleee 7/6/2018
如果你需要经常这样做,速度很重要,但我们大多数人发现自己一年最多只做几次。安装最新的 spiffy 第三方 juju 工具是矫枉过正的,无论如何,自 1978 年以来没有太大变化的解决方案都很好。
1赞 hughdbrown 10/6/2018
我发现程序员每年只在源代码树中搜索几次文本是非常难以置信的。但即使从可用性的角度来看,也比从头开始拼凑递归 grep 命令具有相当大的优势。用:。使用 unix 工具: .如果您的任何文件中有引号,则需要使用 .如果你每年使用几次,你会记住吗?rgrgrg foofind . | xargs grep foofind . -print0 | xargs -0 grep foo
2赞 tripleee 10/6/2018
如果你经常使用这些工具,你就会忘记哪个确实很容易记住。但是,如果您需要经常查找内容,您可能无论如何都应该运行或在源代码树上运行。find . -type f -exec grep 'regex' {} +ctagsetags
1赞 hookenz 7/2/2019
我一直在使用 ripgrep,它很棒。但是银色搜索器对程序员来说非常棒。+1
36赞 kenorb 4/11/2018 #22

通配 **

使用有效,但可能会矫枉过正,尤其是在大文件夹中。grep -r

为了更实际的用法,这里是使用通配语法()的语法:**

grep "texthere" **/*.txt

它仅使用具有模式选择模式的特定文件。它适用于受支持的 shell,例如 Bash +4zsh

要激活此功能,请运行:。shopt -s globstar

Смотритетакже: 如何在 Linux 上找到包含特定文本的所有文件?

git grep

对于 Git 版本控制下的项目,请使用:

git grep "pattern"

这要快得多。

ripgrep

对于较大的项目,最快的 grepping 工具是 ripgrep,它默认以递归方式 greps 文件:

rg "pattern" .

它建立在 Rust 的正则表达式引擎之上,该引擎使用有限自动机、SIMD 和激进的文字优化来使搜索变得非常快。在此处查看详细分析

评论

4赞 Basya 6/6/2018
感谢您的 git grep 建议 - 它非常有用,我不知道它!
4赞 What Would Be Cool 1/25/2019
感谢您的 ripgrep 建议。它的速度要快得多。
6赞 Zstack 11/18/2019 #23

把我的两分钱扔在这里。正如其他人已经提到的,grep -r 并非适用于每个平台。这听起来可能很傻,但我总是使用 git。

git grep "texthere"

即使目录没有暂存,我也只是暂存它并使用 git grep。

2赞 Shreesh Mohan Verma 7/29/2020 #24

对于 .gz 文件,以递归方式扫描所有文件和目录 更改文件类型或放置 *

find . -name \*.gz -print0 | xargs -0 zgrep "STRING"
13赞 geek 4/20/2021 #25

另一种语法,用于递归地在 Linux 系统上的所有文件中 grep 字符串

grep -irn "string"

命令的细分

 -r, --recursive

表示在给定目录和子目录中查找指定字符串的搜索,以查找文件、二进制文件等中的特定字符串recursive

-i, --ignore-case

忽略区分大小写,可用于添加倒置大小写字符串

-n, --line-number

打印找到的文件中指定字符串的行号

注意:这会将大量结果打印到控制台,因此您可能需要通过管道过滤输出并删除不太有趣的信息。它还搜索二进制程序,因此您可能需要过滤一些结果

1赞 Kasthuri Shravankumar 2/16/2023 #26

从 grep 命令获取第一个匹配的文件,并获取所有文件不包含某些单词,但第二个 grep 的输入文件来自第一个 grep 命令的结果文件。

grep -l -r --include "*.js" "FIRSTWORD" * | xargs grep "SECONDwORD"
grep -l -r --include "*.js" "FIRSTWORD" * | xargs grep -L "SECONDwORD"

DC0FD654-37DF-4420-8BA5-6046A9DBE406

grep -l -r --include "*.js" "SEARCHWORD" * | awk -F'/' '{print $NF}' | xargs -I{} sh -c 'echo {}; grep -l -r --include "*.html" -w --include=*.js -e {} *;  echo '''

5319778A-CEC2-444D-BCC4-53D33821联邦快递

grep "SEARCH_STRING" *.log | grep -e "http" -e "https" | awk '{print $NF}' | uniq

CE91D131-A5C2-4CC8-B836-1461FEEE6CDB

下面介绍如何修改命令以提取 messageName 的值:

grep -m 2 "In sendMessage:: " *LOGFILE.log | grep -o -e "messageName=[^,]*" | cut -d= -f2 | sort | uniq | tee >(echo "Number of unique values: $(wc -l)")

grep "In Message:: " *messaging.log | grep -o -e "messageName=[^,]*" | cut -d= -f2 | sort | uniq | while read -r messageName; do grep -m 1 "In  sendMessage:: .*messageName=${messageName}" *logfile.log | head -n 1; done

我想在上面的文件上使用 run below grep 命令 2. 文件根据更新时间降序排序,与 .gz 格式不匹配

grep "org.springframework.batch.item.ItemStreamException: Failed to initialize the reader at" $(ls -lrth | grep -i opti | awk '{print $NF}')
      grep -A 15 "request to URL : SEARCH" $(ls -lth | grep "common" | grep -v ".gz"  | awk '{print $NF}')

命令创建从第一次出现到最后一次出现的新文件。

sed -n '/14 Jan 2023/,/14 Jan 2023/p' common.log > common_1day.log

今天修改的文件,

ls -lrth $(find . -type f -name "*.log" -newermt "$(date -R -d 'today 00:00')" -print)
grep "CID" $(find . -type f -name "*.log" -newermt "$(date -R -d 'today 00:00')" -print)
zgrep "SEARCH" $(find . -type f -newermt "$(date -R -d 'today 00:00')" -print)
ls -lrth $(find . -type f -name "*" -newermt "$(date -R -d 'today 00:00')" -print)
less +G $(find . -type f -name "*LOG_FILE.log" -newermt "$(date -R -d 'today 00:00')" -print)
grep Async $(find . -type f -name "*" -newermt "2023-04-14 00:00:00" ! -newermt "2023-04-16 00:00:00" -print)

查找命令

find . -type f -not -path "*/target/*" -name "log4j2.xml" -exec grep -H '<Async name="' {} \;
1赞 access_granted 4/26/2023 #27

在 Solaris(可能还有其他旧的 Unix)上

ggrep -r “$yourtext” $directory