57

I'm trying to look for a file called Book1.

In my test I'm trying to look for the aforementioned file and in this test, I don't know where that file is located.

I tried find / -iname book1 but there is no output.

How do I find my file called book1 using the command line if I don't know where the file is located?

EDIT:

My scenario is described in more detail below:

  1. The file extension is unknown
  2. The exact name (i.e. Capitalized letters, numbers, etc.) is unknown
  3. The location of the file is unknown
4
  • 2
    If there is a file called Book1, and it is in a directory you can read, then find / -iname book1 will find it. Are you sure it is actually Book1, and not Book1.xyz?
    – Fox
    Apr 30, 2017 at 17:33
  • The complete name of the file is Book1.gnumeric. Are you saying that I have to specify the entire name of the file? For some reason I thought, for this specific command, that all I'd need is the general name of the file. My test is trying to find a file if for example, I don't remember the file extension and only kind of know the name of the file I'm looking for. Please advise.
    – Nina G
    Apr 30, 2017 at 17:37
  • @don_crissti Done. Please see above Edit.
    – Nina G
    Apr 30, 2017 at 17:54
  • You’re mixing find and locate. locate is generous, and will find anything which matches, as long as it is in its database, which is normally updated daily. find, in this case, is looking for a file glob, the sort of pattern you would use in ls. You probably mean iname '*book1*'. Note that the pattern must be inside quotes to stop the shell from expanding it before find gets to see it. Also notice that find, like many *nix commands, is frustratingly silent when it is unsuccessful.
    – Manngo
    May 1, 2017 at 11:48

10 Answers 10

74

First, an argument to -iname is a shell pattern. You can read more about patterns in Bash manual. The gist is that in order for find to actually find a file the filename must match the specified pattern. To make a case-insensitive string book1 match Book1.gnumeric you either have to add * so it looks like this:

find / -iname 'book1*'

or specify the full name:

find / -iname 'Book1.gnumeric'

Second, -iname will make find ignore the filename case so if you specify -iname book1 it might also find Book1, bOok1 etc. If you're sure the file you're looking for is called Book1.gnumeric then don't use -iname but -name, it will be faster:

find / -name 'Book1.gnumeric'

Third, remember about quoting the pattern as said in the other answer.

And last - are you sure that you want to look for the file everywhere on your system? It's possible that the file you're looking for is actually in your $HOME directory if you worked on that or downloaded it from somewhere. Again, that may be much faster.

EDIT:

I noticed that you edited your question. If you don't know the full filename, capitalization and location indeed you should use something like this:

find / -iname 'book1*'

I also suggest putting 2>/dev/null at the end of the line to hide all *permission denied* and other errors that will be present if you invoke find as a non-root user:

find / -iname 'book1*' 2>/dev/null

And if you're sure that you're looking for a single file, and there is only a single file on your system that match the criteria you can tell find to exit after finding the first matching file:

find / -iname 'book1*' -print -quit 2>/dev/null
1
8

You may try the locate command. It uses a database of filenames to make searching quicker.

To search for all file matching *book1*, and ignoring case, you could use

locate -i book1

if you want to search for files starting with book1 you will need to do the wildcard yourself:

locate -i 'book1*'

It is much faster than find, but is only as up-to-date as the last time the database was refreshed.

1
  • None of these produced any output for me: locate -i after.sh, sudo locate -i "after.sh", sudo locate -i after.sh, sudo locate -i '*after.sh'
    – Ryan
    Mar 11, 2020 at 16:07
6

If you know you have a file called book1.something, where the file location, the exact value of something, and the capitalization pattern of the filename are all unknown:

find / -iname 'book1.*'

If all you know for sure is that the filename contains the word book, you can generate a likely much larger list with

find / -iname '*book*'

The argument to -name is a shell glob pattern. From the directory the file is in, compare:

$ ls Book1
ls: cannot access 'Book1': No such file or directory
$ ls Book1.*
Book1.gnumeric

This represents the kind of search performed by -name. The -iname option simply allows a case-insensitive version of this.

2

POSIXly,

LC_ALL=C find / -name '*[bB][oO][oO][kK]1*'

Will report the path of all files whose name contains book1 (with any variation of case, but only considering the ASCII latin characters bokBOK, not the many other variations in Unicode like 𝗄, 𝚔, 𝘬, , , , and all their variations with diacritics...) in all the directories you have read access to.

2

With Zsh you can use glob patterns, so this works too:

ls -a /**/book1

This will find all locations where a file called book1 lives.

In my testing, this seems to be faster than using find, and it also produces little to no user permission errors when run without root permission

See manual.

1

ag (the silver searcher) provides very fast search in files, and also has an option to search for filename:

>: time ag -g foo # uses heuristics to only look in desired locations
apps/vxy/src/assets/tree-content-pages/tree-page-bird/foo-illustration.jpg

real    0m0.884s
user    0m0.701s
sys     0m0.178s

>: time find . -name "*foo*"
./apps/ssr/dist/static/media/foo-illustration.jpg
./apps/vxy/dist/static/media/foo-illustration.jpg
./apps/vxy/src/assets/tree-content-pages/tree-page-bird/foo-illustration.jpg

real    0m29.744s
user    0m2.108s
sys     0m13.982s

>: time ag -ug foo # searching all files is still faster and simpler to use then find command
apps/ssr/dist/static/media/foo-illustration.jpg
apps/vxy/dist/static/media/foo-illustration.jpg
apps/vxy/src/assets/tree-content-pages/tree-page-bird/foo-illustration.jpg

real    0m16.698s
user    0m1.951s
sys     0m7.119s

So in my use case here it's >30 times faster if the file is not a file ignored by ag.

0

For these kinds of tasks I always do : find / -iregex '.*Book1.*'

This form would take care of the 3 points of your scenario (iregex is a case insensitive rational expression, and the pattern with .* on both side would match any character before and after your fixed pattern of Book1 - this could obviously give you back more results than necessary but you are sure not to miss the file)

The main difference: if possible, be more restrictive than just using /, like trying only /home or so, otherwise you will descend in some directories that are not relevant (/sys, /dev, etc…)

Remember however that Unix permissions apply: if the file is in a directory for which the user running the find command has no access (execute) right, find will not be able to find it there.

1
  • iregex won't work in places like Solaris (OS was not specified) (and possibly *BSD), it is a GNU extension and is not part of standard find Jan 6, 2019 at 9:57
0

Silver Searcher is a very fast and handy util to search for files and content.

To solve your problem the silver searcher command would look like this...

ag -g Book1

-g PATTERN Print filenames matching PATTERN

0

locate and its variants tend to be a fast method.

# updatedb # run as root, possibly using sudo, e.g. sudo -b updatedb. If file is on the system for more than a day it should already be in the index and this can be skipped
$ locate -i book1

If locate is not available, you can use find instead. It tend to be much slower, but also much more precise.

If you have a single partition: (run as root if your user might not have access to the file)

$ find / -xdev -iname 'book1*' -print # If the iname extension to find is available
$ find / -xdev -print | grep -F -i /book1 # if iname is not available

If you do not include -xdev find searches things on other partitions, like /proc and /sys, which tend to flood your screen with errors, especially if you are not root. (Errors can be hidden by appending 2> /dev/null at the end of the find command (the comment should be removed))

If you have multiple partitions and you don't know on which one the file is on, you can get a list with lsblk (on Linux-based OSes, parsing df output is an option otherwise) and feed that into find: (root again if you don't know if you can access the file)

$ find $(lsblk -O MOUNTPOINT -n | grep -F /) -xdev -iname 'book1*' -print # GNU-based OSes
$ find $(df -P|awk '$1 ~ /^\/dev/ {print $NF}') -xdev | grep -F -i book1 # Non-GNU based OSes.

(This is a bit fragile if any of your mountpoints have spaces in) (df parameters might need tuning. -P makes GNU df give standard POSIX output. Other versions might have other parameters or need it left out. Read your man page)

The grep -F excludes other things returned, like swap partitions.

In the non-GNU version, awk find devices with a mount starting with /dev to get real file systems and then print the last field (the mountpoint) from the df output.

This also assumes a bourne-like shell (ksh and bash should work. If you are using a csh variant, start up a scriptable shell before you try this)

1
  • The greps might be a bit noisy, learn how to filter it better (this should not be needed with the example, but if it is something more common that is looked for, the greps would need tuning to keep the noise levels down) Jan 6, 2019 at 10:01
0
find /  -type f -iname "book[0-9].*" 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .