题 如何在Linux上找到包含特定文本的所有文件?


我正在尝试找到一种方法来扫描整个Linux系统,查找包含特定文本字符串的所有文件。只是为了澄清,我在文件中寻找文本,而不是文件名。

当我查找如何做到这一点时,我遇到了两次这个解决方案:

find / -type f -exec grep -H 'text-to-find-here' {} \;

但是,它不起作用。它似乎显示系统中的每个文件。

这是否接近正确的方法呢?如果没有,我该怎么办?这种在文件中查找文本字符串的能力对于我正在做的一些编程项目非常有用。


3693
2018-06-06 08:06


起源


记得grep会解释任何 . 作为单字符通配符等。我的建议是总是使用fgrep或egrep。 - Walter Tross
无论如何,你几乎就在那里!只需更换 -H 同 -l (有可能 grep 同 fgrep)。排除具有您将使用的某些名称模式的文件 find 以更先进的方式。学会使用它是值得的 find但是。只是 man find。 - Walter Tross
find … -exec <cmd> + 更容易打字和更快 find … -exec <cmd> \;。它只适用于 <cmd> 接受任意数量的文件名参数。如果,执行时间的节省特别大 <cmd> 像Python或Ruby脚本一样开始很慢。 - hagello
要在给定路径中非递归地搜索,命令是`grep --include = * .txt -snw“pattern”thepath / *。 - Stéphane Laurent
@StéphaneLaurent我认为你太复杂了。说啊 grep "pattern" path/*.txt - fedorqui


答案:


请执行下列操作:

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r 要么 -R 是递归的,
  • -n 是行号,和
  • -w 代表整个单词的匹配。
  • -l (小写L)可以添加到只给出匹配文件的文件名。

除此之外, --exclude--include--exclude-dir flags可用于高效搜索:

  • 这只会搜索那些具有.c或.h扩展名的文件:

    grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
    
  • 这将排除搜索所有以.o扩展名结尾的文件:

    grep --exclude=*.o -rnw '/path/to/somewhere/' -e "pattern"
    
  • 对于目录,可以排除特定目录 --exclude-dir 参数。例如,这将排除目录dir1 /,dir2 /以及所有匹配* .dst /:

    grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/somewhere/' -e "pattern"
    

这对我来说非常有效,可以达到和你一样的目的。

有关更多选项,请检查 man grep


6681
2018-06-06 08:21



使用--exclude。比如“grep -rnw --exclude = *。o'目录'-e”模式“ - rakib_
我发现grep的--include参数非常有用。例如:grep -rnw --include = * .java。 -e“无论我在寻找什么” - Lucas A.
值得注意的是:它似乎是 r 选项是懒惰的(遍历深度优先,而不是在第一个目录之后停止),而 R 贪婪(将正确遍历整个树)。 - Eliran Malka
注意(特别是对于新手):上述命令中的引号很重要。 - madD7
@Eliran Malka R 恩 r 将正确遍历目录,但是 R 将遵循符号链接。 - bzeaman


您可以使用 grep -ilR

grep -Ril "text-to-find-here" /
  • i 代表忽略大小写(在您的情况下是可选的)。
  • R 代表递归。
  • l 代表“显示文件名,而不是结果本身”。
  • / 代表从机器的根开始。

1087
2018-06-06 08:08



根据我的经验, -i 使它减慢很多,所以如果没有必要,不要使用它。在某个目录中测试然后进行推广。它应该在几分钟内完成。我认为正则表达式会使它变慢。但我的评论是基于假设,我建议你用它来测试 time 在线前。 - fedorqui
是, /* 代表着这一点。无论如何,我只是测试了它并注意到了 / 作品。 - fedorqui
如果您不使用正则表达式进行搜索,则可以在大多数系统上使用fgrep代替grep。 - markle976
是的,@ markle976,实际上来自man grep: fgrep is the same as grep -F -> Interpret PATTERN as a list of fixed strings。 - fedorqui
您可以将/替换为目录路径 grep -Ril "text-to-find-here" ~/sites/ 或使用。对于当前目录 grep -Ril "text-to-find-here" . - Black


您可以使用 ACK。它像是 grep的 用于源代码。您可以使用它扫描整个文件系统。

做就是了:

ack 'text-to-find-here'

在根目录中。

你也可以使用 常用表达,指定文件类型等。


UPDATE

我刚刚发现 银色搜索者,这就像ack但比它快3-5倍,甚至忽略了a的模式 .gitignore 文件。


234
2018-06-06 08:26



非常有用,简单而快速。警告:“在Debian派生的发行版上,ack被打包为”ack-grep“因为”ack“已经存在”(来自 beyondgrep.com/install)。您最终可能会在这些Linux上运行一个汉字代码转换器...... - Jose_GD
ack或ack-grep有很好的亮点,但是当正确使用时性能要好得多,找到+ grep - Sławomir Lenart
注意 ripgrep 比这里提到的任何其他东西都要快,包括The Silver Searcher和简单的'ol grep。看到 这篇博文 证明。 - Radon Rosborough


您可以使用:

grep -r "string to be searched"  /path/to/dir

r 代表递归,因此将在指定的路径及其子目录中进行搜索。这将告诉您文件名以及打印出字符串出现的文件中的行。

或者类似于您正在尝试的命令(例如:)用于搜索所有javascript文件(* .js):

find . -name '*.js' -exec grep -i 'string to search for' {} \; -print

这将在文本出现的文件中打印行,但不会打印文件名。

除了这个命令,我们也可以这样写: grep -rn“要搜索的字符串”/ path / to / directory /或/ file -r:递归搜索 n:将显示匹配的行号


126
2018-03-14 23:29



Thanx为查找版本。我的grep版本(busybox for NAS)没有-r选项,我真的需要另一个解决方案! - j.c
谢谢你的'发现'版本!能够通过'过滤非常重要.js'或'.txt'等。没有人愿意花几个小时等待grep来完成搜索上一次家庭度假的所有多GB视频,即使命令更容易输入。 - mightypile


你可以用这个:

grep -inr "Text" folder/to/be/searched/

83
2017-07-31 13:44



最简单,冗长,递归和不区分大小写。竖起大拇指。 - Francesco Casula
如果添加-A3甚至更好 - albanx
那很酷。 - kodmanyagha


包含给定文本的文件名列表

首先,我相信你已经习惯了 -H 代替 -l。您也可以尝试在引号后面添加文本 {} \

find / -type f -exec grep -l "text-to-find-here" {} \; 

假设您正在目录中搜索包含特定文本“Apache License”的文件。它将显示与下面类似的结果(输出将根据您的目录内容而有所不同)。

bash-4.1$ find . -type f -exec grep -l "Apache License" {} \; 
./net/java/jvnet-parent/5/jvnet-parent-5.pom
./commons-cli/commons-cli/1.3.1/commons-cli-1.3.1.pom
./io/swagger/swagger-project/1.5.10/swagger-project-1.5.10.pom
./io/netty/netty-transport/4.1.7.Final/netty-transport-4.1.7.Final.pom
./commons-codec/commons-codec/1.9/commons-codec-1.9.pom
./commons-io/commons-io/2.4/commons-io-2.4.pom
bash-4.1$ 

区分大小写敏感度

即使你没有使用像“text”和“TEXT”这样的情况,你也可以使用 -i 切换到忽略大小写。您可以阅读更多详细信息 这里

希望这对你有所帮助。


50
2017-11-09 13:18



OP要求提供包含内容中文本而非文件名的文件。 - Auxiliary
这个命令的作用是什么: find 将它找到的所有路径传递给命令 grep -l "text-to-find-here" <file found>"。您可以对文件名添加限制,例如 find / -iname "*.txt" 仅搜索名称结尾的文件 .txt - Mene
@Auxiliary - 包含一个示例输出,以避免给读者带来任何混淆。 - lkamal
@Mene这是一个非常悲伤的状态,Auxiliary的评论比你的评论更多......即使他们的评论来自2014年,而你的评论是2017年,他们的评论有6分,当它应该有0而你的只有一个(现在是2)isn我想要相信的东西。 - Pryftan
@Mene有人说 -iname 不区分大小写,这意味着它也会找到.TXT文件,例如TxT和TXt等。 - Pryftan


如果你的 grep 不支持递归搜索,你可以结合使用 find 同 xargs

find / -type f | xargs grep 'text-to-find-here'

我发现这比格式更容易记住 find -exec

这将输出文件名和匹配行的内容,例如

/home/rob/file:text-to-find-here

您可能想要添加的可选标志 grep

  • -i  - 不区分大小写的搜索
  • -l  - 仅输出找到匹配项的文件名
  • -h  - 只输出匹配的行(不是文件名)

47
2018-06-20 08:49



这相当于 grep 'text-to-find-here' 如果没有文件名 find 找不到任何东西。这将挂起并等待用户输入!加 --no-run-if-empty 作为一种选择 xargs。 - hagello
如果文件或目录名称包含空格(xargs解释为分隔符的字符),则find和xargs的这种组合不会按预期工作。使用 find … -exec grep … +。如果您坚持将find与xargs一起使用,请使用 -print0 和 -0。 - hagello


grep -insr "pattern" *
  • i:忽略PATTERN和输入文件中的大小写区别。
  • n:在输入文件中使用基于1的行号为每行输出添加前缀。
  • s:禁止有关不存在或不可读文件的错误消息。
  • r:递归地读取每个目录下的所有文件。

34
2018-02-26 05:47



你能解释一下你的答案如何改进其他答案,或者它们与它们有多大的不同? - Amos M. Carpenter
没有太多复杂的记忆,将涵盖所有模式(案例敏感 - >关闭,包括文件名和行号,并将进行递归搜索等)和使用“*”最后将搜索所有目录(无需指定任何路径或目录名称)。 - enfinet
对不起,我应该更清楚一点:如果你能在答案中包含这些解释,那将会很棒。就目前而言,特别是在已有如此多的其他类似答案的情况下,很难从如此简短的回答中看出尝试的好处 它 超过接受的答案或其中一个赞成的答案。 - Amos M. Carpenter
这是一个很好的答案+很好的解释 - khelili miliana
@ AmosM.Carpenter我喜欢这个答案的一件事是指出抑制论证,它可以帮助滤除与获得我们实际想要的结果无关的噪音。 Grep在某些“文件”上打印诸如“功能未实现”,“无效参数”,“资源不可用”等错误。 - leetNightshade


grep (GNU 要么 BSD

您可以使用 grep 用于递归搜索当前文件夹的工具,如:

grep -r "class foo" .

注意: -r  - 递归搜索子目录。

您还可以使用通配语法在特定文件中进行搜索,例如:

grep "class foo" **/*.c

注意:使用 全球选项 (**),它以特​​定的扩展名或模式递归扫描所有文件。 要启用此语法,请运行: shopt -s globstar 你也可以使用 **/*.* 对于所有文件(不包括隐藏和没有扩展名)或任何其他模式。

如果您的错误是您的参数太长,请考虑缩小搜索范围或使用 find 语法代替如:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

或者使用 ripgrep

ripgrep

如果您正在处理更大的项目或大文件,您应该使用 ripgrep 相反,像:

rg "class foo" .

查看文档,安装步骤或源代码 GitHub项目页面

它比任何其他工具都快得多 GNU/BSD  grepucgagsiftackpt 或类似的,因为它建立在 Rust的正则表达式引擎 它使用有限自动机,SIMD和积极的文字优化来快速搜索。

它支持忽略指定的模式 .gitignore 文件,因此单个文件路径可以同时与多个glob模式匹配。


您可以使用常用参数,例如:

  • -i  - 不敏感的搜索。
  • -I  - 忽略二进制文件。
  • -w  - 搜索整个单词(与部分单词匹配相反)。
  • -n  - 显示你的比赛线。
  • -C/--context (例如。 -C5) - 增加上下文,以便您查看周围的代码。
  • --color=auto  - 标记匹配的文本。
  • -H  - 显示找到文本的文件名。
  • -c  - 显示匹配行的计数。可以结合使用 -H

29
2018-05-09 10:11



我也发现扩展的globbing非常有用。但请记住,如果确实存在大量文件,则可能会出现“参数列表太长”错误。 (简单的globbing也容易出现这种错误)。 - Yoory N.


尝试:

find . -name "*.txt" | xargs grep -i "text_pattern"

24
2017-12-10 05:47



这实际上是不使用时的一个主要例子 xargs 那样..考虑一下。 echo "file bar.txt has bar" > bar.txt; echo "file foo bar.txt has foo bar" > "foo bar.txt"; echo "You should never see this foo" > foo; find . -name "*.txt" | xargs grep -i foo # ./foo:You should never see this foo 。该 xargs 这里匹配WRONG文件并且与预期文件不匹配。要么使用a find .. -print0 | xargs -0 ... 但这是无用的管道或更好的 find ... -exec grep ... {} + - shalomb


使用 pwd 从您所在的任何目录中搜索,向下递归

grep -rnw `pwd` -e "pattern"

更新 根据您使用的grep版本,您可以省略 pwd。在较新的版本 . 如果没有给出目录,似乎是grep的默认情况 从而:

grep -rnw -e "pattern" 

要么

grep -rnw "pattern" 

会做同上面的事情!


22
2018-05-28 12:47



运用 pwd 根本不需要,因为它是默认值。 grep -rnw "pattern" 就足够了。 - fedorqui
事实上 grep -rnw和三年前的回答类似,我看不出这个答案是如何增加价值的。 - fedorqui
选定的答案没有显示默认模式,5个人似乎发现它很有用 - mahatmanich
“默认模式”是什么意思?接受的答案包含 grep -rnw '/path/to/somewhere/' -e "pattern" 这就是你在这里。 2.3M访问后的5票并不意味着那么多。 - fedorqui
我同意:-)我在原始答案中缺少的是用例,您根本不需要提供路径或递归搜索当前目录,这不会反映在接受的答案中。因此,深入挖掘grep是一个很好的学习经验。 - mahatmanich