# How to search a file in a particular system using Mathematica

I want to know if there is any function which can search a file from the whole system and gives the whole path for that particular file. I have tried \$Path but it gives some default paths also.

If the file is stored in multiple locations and I want only one location out of all, how can I get that?

I want to stop the search as soon as the file is found.

-

Sure, use FileNames:

FileNames["myfile.doc", {"C:\\"}, Infinity]


This finds any files named myfile.doc on drive C:.

Add other drives as needed to the list: {"C:\\", "D:\\", . . .}

File names can be given as literal strings, StringExpression string patterns, RegularExpression objects, or abbreviated string patterns.

A method to abort the search after the first result is found was requested.

findFirstFile[name_, path_, level_: Infinity] :=
FileNames[
x__ /; If[x ~StringMatchQ~ name,
FileNameJoin@{Directory[], x} ~Return~ FileNames],
path, level]


Usage:

findFirstFile["report*.doc", "A:\\"]


Mathematica does not search the root directory of the given path first, as I would expect.
At the cost of scanning that directory twice we can force this behavior.

findFirstFile[name_, path_, level_: Infinity] :=
FileNames[#, path, 1] /. {} /; level > 1 :> FileNames[#, path, level] &[
x__ /; If[x ~StringMatchQ~ name, FileNameJoin@{Directory[], x} ~Return~ FileNames]
]

-
If the file is stored in multiple locations and I want only one location out of all. How can I get that? –  Jennifer Jul 18 '12 at 5:37
@Jennifer you could use use // First after the other code. Or do you mean you want to stop the search as soon as one file is found? –  Mr.Wizard Jul 18 '12 at 5:43
I want to stop the search as soon as the file is found... –  Jennifer Jul 18 '12 at 5:50
@Jennifer okay, good question. I don't know how to do that with FileNames. Are you open to using external (command line) tools? What OS do you use? –  Mr.Wizard Jul 18 '12 at 5:51
Thanks.... No, I wanted to do this by Mathematica itself. Windows7 –  Jennifer Jul 18 '12 at 5:54

The most efficient way to solve probably depends on the operating system you are running Mathematica on. Linux offers an efficient way of finding one of more files using a regular expression file specification.

In it's simplest form the solution resolves to the following which stops once it has found one file:

findAFile[name_String, path_String: "/"] :=
ReadList["!find " <> path <> " -name \"" <> name <> "\" -print -quit", String]


An example of use would be:

findFiles["*[1-3].JPG"]


{"/data/bitmaps/for_filing/S1010001.JPG"}

This uses the ability of ReadList to directly take an operating system command, in this case find, run that command and return its output.

A more general solution allowing use of find's extensive options:

Options[findFiles] = {FindOptions -> "-print -quit"};
findFiles[name_String, path_String: "/",OptionsPattern[]] :=
ReadList["!find "<> path <> " -name \"" <> name <> "\" "<> OptionValue@FindOptions, String]


To find the first N files it is simple to use linux's head command as an option:

findFiles["*.jpg", "/mnt/ls3/data/bitmaps/animals", FindOptions -> " | head -4"]


{"/data/bitmaps/animals/birds/waterfowl/dsc04802.jpg", "/data/bitmaps/animals/birds/waterfowl/dsc04803.jpg", "/data/bitmaps/animals/birds/waterfowl/dsc04804.jpg", "/data/bitmaps/animals/birds/waterfowl/dsc04805.jpg"}

Whilst the following would find only the directories below the given path:

   findFiles["*", "/data/bitmaps/animals", FindOptions -> " -type d "]


{"/data/bitmaps/animals","/data/bitmaps/animals/birds","/data/bitmaps/animals/birds/general"}

>

Background

In the Linux case the operating system provides support for finding files in a number of ways.

Probably the most used of these are ls, find and locate.

find has a host of options to select by date, type, owner, depth, size and more. It allows logical combinations of options and even execution of commands on the found files. It offers a much richer search method than Mathematica's FindFile or FileNames, find.

Without too much effort we can leverage that capability.

Finding the first file

Linux offers several ways to find the first, or N, file(s) from a list.

Forcing find to abort after it's first result:

find / -name "*.jpg -print -quit "

By aborting find when head ( which just prints the first N lines of it's input ) has fulfilled it's line specification:

find / -name "*.jpg | head -1 "

Replacing -1 with -2 , -3 and so on, will return the first 2, 3 etc files found.

The specific file returned will depend upon the search order of directories which is system dependent. The search order for any system can be determined by:

find path -type d where path represents the starting point in the directory structure for find to begin its search. Typically that might be the filesystem root directory / as in the previous examples.

An alternative approach using locate, which may have a different search order for directories, can be adopted with:

locate *.jpg --limit=1

-
Now if anyone knows of a good search command for the Windows world, using dir or something else perhaps, I'll expand the answer to implement that. –  image_doctor Jul 18 '12 at 10:59
Concerning efficiency it might be worth noting that AFAIK locate searches within a database which is updated every now and then, while find really searches the file system. So locate will usually be much faster, but the data it searches can't be guaranteed to be up to date at any given moment... –  Albert Retey Jul 20 '12 at 18:34
@AlbertRetey, good point, would you know if non-local filesystem have their own locate cache which can be utilised ... or does the local locate have to keep track of the remote file structure? –  image_doctor Jul 20 '12 at 20:52
These databases are not, AFAIK, in any way part of the filesystem but just created on top of it (with a program called updatedb called as a cron job typically). It is possible to tell locate which database(s) it should use, so it would be possible to have one database per remote filesystem and update those databases locally. I have no experience on how to set up something like that decently and how well that would work, though. I could imagine that for such cases there could be tools available that would fit even better... –  Albert Retey Jul 21 '12 at 13:50
@AlbertRetey thanks for that, caching locally a remote file system might be time consuming and a cache to cache communication mechanism would be neat if it existed. But maybe the OP doesn't need that much complexity. –  image_doctor Jul 21 '12 at 15:25