11

My goal is to find all pdf files on a remote machine, so I resort to the useful command find. So I type

find ~ *.pdf
or
find ~ "*.pdf"
and I get nothing. I do the same on my machine and I get nothing. I do a regular search from the menu on my machine and I find quite a few pdf files. Would somebody please tell me what am I doing wrong?

8
  • 12
    Keep your negative opinions outside your question if you want a good response. In a related story, find is far from useless. May 25, 2010 at 23:31
  • 8
    Of course you have the right of free speech. But you do want a good response, right? No, you don't have a right for a good constructive response. That is a privilege. May 25, 2010 at 23:39
  • 2
    A bad workman always blames his tools. In other words, pure PBCAK here. May 25, 2010 at 23:39
  • 5
    @Wilhelmtell, I think Martin's statement is fair -- the command should never have been named "find" in the first place, more like "walkpath_and_execute"... it doesn't have the most intuitive or user friendly interface and does far more than simply find files. The simple name "find" is deceptive in that it suggests a simple interface which it doesn't have. Sure, find is far from useless and works quite well, but one can hardly blame a beginner for not knowing the difference between "find", "locate", "which", etc. May 25, 2010 at 23:46
  • 1
    @Michael I didn't blame anyone here; or, rather, I wasn't the one doing the blaming here. I didn't even say find is intuitive. I could probably say the same thing in a nicer tone though; sometimes I react to (silly) negative comments. May 26, 2010 at 0:04

7 Answers 7

35

find is far from useless. You are just not using it properly.

try:

find . -type f -iname '*.pdf'

2
  • @Martin - Happy to help, just be sure to mark the question as answered! May 26, 2010 at 18:19
  • @stepancheg Yes, why don't you take down the internet and print a hard copy.
    – bobobobo
    May 10, 2011 at 3:51
10

Take a look at the documentation for the findutils. The find command is an incredibly powerful one and, consequently, has a somewhat complicated interface. You can do what you want with:

find . -type f -iname '*.pdf' 

The command above means "find within . for entries of type file with a case insensitive name matching *.pdf (and print the name of such matches)". The find command can actually be used to execute commands on the files that are found (instead of or in addition to printing the file names). For your purposes, though, you may find yourself more comfortable with the locate command, which -- assuming you have built up the locate database using updatedb -- makes it very easy to find files. For example:

locate '*.pdf'

You will also find that the locate command is typically faster than the find command as locate uses an index of filenames (the locate database), whereas find will walk the hierarchy for each invocation.

6

You're simply missing the predicate that says what you're searching by (e.g. -name.)

To find in home directory by name:

find ~ -name \*.pdf

Note that the wildcard * has to be escaped so that the shell doesn't interpret it before find gets its hands on it. Using '*.pdf' and "*.pdf" will have the same effect as \*.pdf.

To find case-insensitively:

find ~ -iname \*.pdf

To prune the results to files only (the name expression will probably take care of this for you, but just in case you have any weirdly-named directories):

find ~ -type f -iname \*.pdf

To make sure find follows symbolic links (I usually want to do this myself when doing searches):

find ~ -follow -type f -iname \*.pdf

To do something with the files you found: you can dump this to a file using stdout redirection (e.g. tack on > filename at the end), or use the -exec option to run a command (see the man page for details). The latter runs a command on each file at a time, though. it's often faster to let the xargs command pass your found files as arguments to another command, all at once or big chunks at a time. For example, for ad-hoc (but unindexed) greps through header files:

find ~ -follow -type f -name \*.h | xargs grep -nH "identifier"

And one final extension, to make that last command work properly if you have files & directories with spaces in them:

find ~ -follow -type f -name \*.h -print0 | xargs -0 grep -nH "identifier"
3
  • Actually, "*.pdf" would expand if there are files in the current directory ending with .pdf, right? (minor note) May 26, 2010 at 9:00
  • 1
    Not in bash. From the bash manual: "Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of [dollar], [backquote], [pipe], and, when history expansion is enabled, [bang]." Try it yourself to confirm: ls "*.txt" on a directory with text files in it.
    – Owen S.
    Jun 9, 2012 at 1:35
  • Yes, you are right, of course. I don't know where I got that idea from. Thanks for correcting me. Jun 11, 2012 at 12:22
3

take a look at this tutorial

i think what you want to do is

find . -name "*.pdf"
1
  • You should use the iname attribute for better hallway vision May 25, 2010 at 23:53
0

I used to combine the find with grep like

find . . | grep -i ".pdf"

maybe is not top efficient, but it does the job fine.

1
  • This could be done in find directly if you wished, via -iregex: find ~ -iregex '.*\.pdf'. The problem is, in find the pattern is treated like it always has a ^ at the front and a $ at the back, so your pattern needs to be a bit more complicated. Also note: that . in your pattern is actually a single-character wildcard, not a literal period.
    – Owen S.
    Jun 9, 2012 at 18:37
0

Find files you need downloaded within last x days

find ~ -type f -iname '*.pdf' -mtime -1

will find you pdf files in your home ~ directory and below with extension .pdf regardless of upper and lower case (thats i in iname) and modified up to 1 day ago because I have added mtime -1; if you put -60 in mtime it will be the last 60 days.

0

To execute a search within the "found" files there is this construction:

find <dir> -type f -iname <name> -exec grep -H <string> {} \;

The exec command must end with the escaped ";" and the -H is needed for grep to print out the file path in addition to the line within the file where "string" is.

You must log in to answer this question.