如何搜索多个PDF文件的内容?

290

我该如何在目录/子目录中搜索PDF文件的内容?我正在寻找一些命令行工具。似乎grep无法搜索PDF文件。


6
由于PDF是一种二进制格式,其中的文本通常被压缩或以多种方式进行编码,因此Grep无法工作。 - mark stephens
4
这是一个图形用户界面解决方案:Adobe Reader,请参见 https://wikispaces.psu.edu/display/training/Search+for+Text+in+Multiple+PDFs+with+Adobe+Reader。 - Martin Thoma
3
好的,我会尽力进行翻译。以下是需要翻译的内容:相关链接:http://unix.stackexchange.com/questions/6704/grep-pdf-files - Flow
4
Adobe Reader可以正常使用,但它不支持索引功能;因此,如果你有很多文件,它的速度会很慢。是否有任何索引解决方案? - Irina Rapoport
15个回答

275

pdfgrep这个工具,它可以准确地执行其名称所示的功能。

pdfgrep -R 'a pattern to search recursively from path' /some/path

我已经用它进行了简单的搜索,效果很好。

(Debian、Ubuntu和Fedora中有相关的软件包。)

自版本1.3.0以来,pdfgrep支持递归搜索。Ubuntu从Ubuntu 12.10(Quantal)开始提供此版本。


1
从Natty(Ubuntu 11.04)及以上版本开始(请参见http://packages.ubuntu.com/search?keywords=pdfgrep&searchon=names&suite=all&section=all) - Martin Thoma
3
pdfgrep 现在已经具有递归选项,包括 -R 选项以跟随符号链接。 - Tobias Kienzler
1
我在Debian 10上使用这个工具时遇到了问题。它无法找到一些可以在evince中找到的字符串。结果证明它相当不可靠。 - Ohumeronen
1
@Ohumeronen 七年过去了,问题仍然存在。结果似乎取决于PDF是如何创建的。因此,pdftotext -raw(虽然已被弃用)似乎有所帮助。 - yasd
2.0版本开始,pdfgrep具有--cache选项,可以大大加快对相同文件进行多次搜索的速度。 - Stefan Schmidt

242

您的发行版应该提供名为pdftotext的实用工具:

find /path -name '*.pdf' -exec sh -c 'pdftotext "{}" - | grep --with-filename --label="{}" --color "your pattern"' \;

在使用pdftotext将内容输出到标准输出时,需要添加"-"选项,否则会输出到文件中。

使用--with-filename--label=选项可以将文件名放在grep的输出中。

可选的--color选项很不错,可以让grep在终端上以彩色模式输出。

(在Ubuntu中,pdftotext由包xpdf-utils或poppler-utils提供。)

如果您想使用GNU grep的功能,而pdfgrep不支持这些功能,则使用pdftotext和grep这种方法具有优势。 注意: pdfgrep-1.3.x支持-C选项以打印上下文行。


1
@Kurt Pfeifle 您所做的编辑“(由-kp-编辑)”无效,因为grep过滤了打印的文件名。 - Raphael Ahrens
@sjr 不好意思,虽然pdfgrep的解决方案对于快速简单的搜索很好,但通常我想要获取一些上下文,因为单独的一行不够有帮助。所以正如我在这个答案中添加的那样:例如,你可以在"你的模式"之前加上-C5选项,以将5行上下文包含在输出中-- pdfgrep不支持这个功能。 - Colin D Bennett
哦,那很酷,很高兴知道尽管大多数人不知道它在做什么,但它仍然有优势。 - sjr
2
@sjr 只是为了记录:我正在使用Ubuntu 12.10和pdfgrep是无用的,它报告了大量垃圾文件。另一方面,您的解决方案很有帮助。所以请不要删除它,即使过去3年了,它仍然很有用! - Ali
我能够在cygwin中使用它,尽管为了将其变成带参数的函数,我不得不将“your_pattern”变成“$1”。 - Koshmaar

36

Recoll是一款出色的全文GUI搜索应用程序,适用于Unix/Linux,支持几十种不同的格式,包括PDF。它甚至可以将查询的确切页码和搜索词传递给文档查看器,因此允许您从其GUI直接跳转到结果。

Recoll还配备了可行的命令行界面和web浏览器界面


2
@Glutanimate 如果您能添加一个与原始问题相关的示例,那将有助于我(以及可能还有其他人):我也想看看如何执行通配符搜索以及如何搜索包括所有子目录的当前目录。在命令行(非GUI)中使用recoll / xapian会是什么样子?谢谢! - nutty about natty
@LeszekŻarna 也许您可以发布一下您测试过的示例? - nutty about natty
recoll用户手册可能包含一些指针,但提供了相当技术性和“离题”的阅读... - nutty about natty
1
@nutty:recoll -t -q dir:pwd ext:pdf 'neuro*' -- stackoverflow 吃掉了反引号。 - medoc

17

我实际使用的pdfgrep版本是1.3.0,它可以执行以下操作:

pdfgrep -HiR 'pattern' /path

执行pdfgrep --help时:

  • H:打印每个匹配的文件名。
  • i:忽略大小写区别。
  • R:递归搜索目录。

它在我的Ubuntu上运行良好。


17

还有一个实用工具叫做 ripgrep-all,它基于 ripgrep

它不仅可以处理PDF文档,还可以处理Office文档和电影等文件类型,并且作者 声称 它比pdfgrep更快。

命令语法可递归搜索当前目录,第二个命令限制只搜索PDF文件:

rga 'pattern' .
rga --type pdf 'pattern' .

7
我制作了这个具有破坏性的小脚本。玩得开心。
function pdfsearch()
{
    find . -iname '*.pdf' | while read filename
    do
        #echo -e "\033[34;1m// === PDF Document:\033[33;1m $filename\033[0m"
        pdftotext -q -enc ASCII7 "$filename" "$filename."; grep -s -H --color=always -i $1 "$filename."
        # remove it!  rm -f "$filename."
    done
}

3
+1. 但是你应该将它输入到 grep 中,而不是使用 $filename. - Raphael Ahrens

4

我喜欢@sjr的回答,但是我更喜欢使用xargs而不是-exec。我发现xargs更加灵活。例如,通过-P选项,我们可以在合适的时候利用多个CPU。

find . -name '*.pdf' | xargs -P 5 -I % pdftotext % - | grep --with-filename --label="{}" --color "pattern"

1
关于xargs的并行处理能力,有一个有趣的观点。请注意,您的--label选项参数将被“字面”解释为“{}”,因为grep命令现在不再在findexec上下文中执行。 - mklement0

2
如果您想使用pdftotext查看文件名,请使用以下命令:

find . -name '*.pdf' -exec echo {} \; -exec pdftotext {} - \; | grep "pattern\|pdf" 

2

首先将所有的pdf文件转换为文本文件:

for file in *.pdf;do pdftotext "$file"; done

然后像平常一样使用 grep。这种方法特别适用于在有多个查询和大量PDF文件时,因为它非常快。


这个,当与 ag https://github.com/ggreer/the_silver_searcher 结合使用时。能够在微秒级别上解析出几个GB的数据。平面文件永存。 - NVRM

2

我曾经遇到相同的问题,因此我编写了一个脚本,可以搜索指定文件夹中所有pdf文件中的字符串,并打印匹配查询字符串的PDF文件。

也许这对你有帮助。

你可以在这里下载它。


也许把脚本放在注释中会更有用? - baxx
我尝试了你的脚本,结果比“pdfgrep”解决方案或sjr的一行代码慢得多,并且即使我使用Ctrl-C终止它,它仍然让我留下一个占用100% CPU 线程的持续进程。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接