How to search contents of multiple pdf files?

LinuxPdfFull Text-SearchGrepDebian

Linux Problem Overview


How could I search the contents of PDF files in a directory/subdirectory? I am looking for some command line tools. It seems that grep can't search PDF files.

Linux Solutions


Solution 1 - Linux

There is pdfgrep, which does exactly what its name suggests.

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

I've used it for simple searches and it worked fine.

(There are packages in Debian, Ubuntu and Fedora.)

Since version 1.3.0 pdfgrep supports recursive search. This version is available in Ubuntu since Ubuntu 12.10 (Quantal).

Solution 2 - Linux

Your distribution should provide a utility called pdftotext:

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

The "-" is necessary to have pdftotext output to stdout, not to files. The --with-filename and --label= options will put the file name in the output of grep. The optional --color flag is nice and tells grep to output using colors on the terminal.

(In Ubuntu, pdftotext is provided by the package xpdf-utils or poppler-utils.)

This method, using pdftotext and grep, has an advantage over pdfgrep if you want to use features of GNU grep that pdfgrep doesn't support. Note: pdfgrep-1.3.x supports -C option for printing line of context.

Solution 3 - Linux

Recoll is a fantastic full-text GUI search application for Unix/Linux that supports dozens of different formats, including PDF. It can even pass the exact page number and search term of a query to the document viewer and thus allows you to jump to the result right from its GUI.

Recoll also comes with a viable command-line interface and a web-browser interface.

Solution 4 - Linux

My actual version of pdfgrep (1.3.0) allows the following:

pdfgrep -HiR 'pattern' /path

When doing pdfgrep --help:

  • H: Print the file name for each match.
  • i: Ignore case distinctions.
  • R: Search directories recursively.

It works well on my Ubuntu.

Solution 5 - Linux

There is another utility called ripgrep-all, which is based on ripgrep.

It can handle more than just PDF documents, like Office documents and movies, and the author claims it is faster than pdfgrep.

Command syntax for recursively searching the current directory, and the second one limits to PDF files only:

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

Solution 6 - Linux

I made this destructive small script. Have fun with it.

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
}

Solution 7 - Linux

I like @sjr's answer however I prefer xargs vs -exec. I find xargs more versatile. For example with -P we can take advantage of multiple CPUs when it makes sense to do so.

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

Solution 8 - Linux

I had the same problem and thus I wrote a script which searches all pdf files in the specified folder for a string and prints the PDF files wich matched the query string.

Maybe this will be helpful to you.

You can download it here

Solution 9 - Linux

If You want to see file names with pdftotext use following command:

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

Solution 10 - Linux

First convert all your pdf files to text files:

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

Then use grep as normal. This is especially good as it is fast when you have multiple queries and a lot of PDF files.

Solution 11 - Linux

There is an open source common resource grep tool crgrep which searches within PDF files but also other resources like content nested in archives, database tables, image meta-data, POM file dependencies and web resources - and combinations of these including recursive search.

The full description under the Files tab pretty much covers what the tool supports.

I developed crgrep as an opensource tool.

Solution 12 - Linux

You need some tools like pdf2text to first convert your pdf to a text file and then search inside the text. (You will probably miss some information or symbols).

If you are using a programming language there are probably pdf libraries written for this purpose. e.g. http://search.cpan.org/dist/CAM-PDF/ for Perl

Solution 13 - Linux

try using 'acroread' in a simple script like the one above

Solution 14 - Linux

Thanks for all the good ideas here!

I tried the xargs method, but as pointed out here, xargs will make it impossible (or very hard) to include printing the actual file name...

So I tried the whole thing with GNU parallel.

parallel "pdftotext -q {} - | grep --with-filename --label='['{}']' --color=always --context=5 'pattern'" ::: *.pdf
  • This prints not only the pattern, but with --context=5 also 5 lines above and below as well for context.
  • With -q pdftotext won't print any error messages or warnings (quiet).
  • I use brackets [] as labels instead of braces {}. If you wanted braces --label='{'{}'}' will make that happen. Note that {} is replaced by the actual filename by GNU parallel, e.g. 'Example portable document file name with spaces.pdf' ({} is already using single quotes ').
  • By using --label={} only the filename will be printed, which may be the favored way of displaying the filename.
  • I also noticed that the output was without color when I tried it, except when forcing it by adding --color=always with grep.
  • It may be useful to add --ignore-case to the grep command for a case-insensitive keyword search.

If all PDF files should be processed recursively, including all sub-directories in the current directory (.), this can be accomplished through find:

find . -type f -iname '*.pdf' -print0 | parallel -0 "pdftotext -q {} - | grep --with-filename --label='['{}']' --color=always --context=5 'pattern'"
  • With find, -iname '*.pdf' acts case-insensitive. With -name '*.pdf' only lower-case .pdf files will be included (the normal case). Since I sometimes also encountered Windows PDF-files with an upper-case .PDF file extension, I tend to prefer -iname...
  • The above command also works with the -print find option (instead of -print0), so it will be line-based (one file name per line), then -0 (NUL delimiter) must be omitted from the parallel command.
  • Again, including --ignore-case in the grep command will make the search case-insensitive.

As a general recommendation when playing with the whole command line, parallel --dry-run will print which commands would be executed.

$ find . -type f -iname '*.pdf' -print0 | parallel --dry-run -0 "pdftotext -q {} - | grep --with-filename --label='['{}']' --color=always --ignore-case --context=5 'pattern'"
pdftotext -q ./test PDF file 1.pdf - | grep --with-filename --label='['./test PDF file 1.pdf']' --color=always --ignore-case --context=5 'pattern'
pdftotext -q ./subdir1/test PDF file 2.pdf - | grep --with-filename --label='['./subdir1/test PDF file 2.pdf']' --color=always --ignore-case --context=5 'pattern'
pdftotext -q ./subdir2/test PDF file 3.pdf - | grep --with-filename --label='['./subdir2/test PDF file 3.pdf']' --color=always --ignore-case --context=5 'pattern'

Solution 15 - Linux

Use:

pdfgrep -HinR 'FWCOSP' DatenModel/

In this command I'm searching for the word FWCOSP inside the folder DatenModel/.

As you can see in the output you can have the file name wit the line numbers:

enter image description here

The options I'm using are:

-i : Ignores, case for matching
-H : print the file name for each match
-n : prefix each match with the number of the page where it is found
-R : same as -r, but it also follows all symlinks.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJestin JoyView Question on Stackoverflow
Solution 1 - LinuxGraeme View Answer on Stackoverflow
Solution 2 - LinuxsjrView Answer on Stackoverflow
Solution 3 - LinuxGlutanimateView Answer on Stackoverflow
Solution 4 - LinuxarkhiView Answer on Stackoverflow
Solution 5 - LinuxoschoudhuryView Answer on Stackoverflow
Solution 6 - LinuxphilView Answer on Stackoverflow
Solution 7 - LinuxDeianView Answer on Stackoverflow
Solution 8 - LinuxPaul WeibertView Answer on Stackoverflow
Solution 9 - LinuxAleksey KontsevichView Answer on Stackoverflow
Solution 10 - LinuxMartin ThomaView Answer on Stackoverflow
Solution 11 - LinuxCraigView Answer on Stackoverflow
Solution 12 - LinuxNylon SmileView Answer on Stackoverflow
Solution 13 - LinuxacathurView Answer on Stackoverflow
Solution 14 - LinuxluttztfzView Answer on Stackoverflow
Solution 15 - LinuxFrancesco MantovaniView Answer on Stackoverflow