« HOWTO:Install BeyondCompare on 64-bit UbuntuBash History, setting it up »

HOWTO: find files on your system

18/10/09

Permalink 12:41:11 pm, by richard Email , 1227 words   English (GB)
Categories: Ubuntu Linux

HOWTO: find files on your system

The find command can be really useful once you know how to use its more powerful options. It can be use in a simple form to find files from your current directory and all the subdirectories below.

find

or to find a specific file one way it to use grep,

find | grep somefilename

A better way is to use find's own name search

find -name somefilename

If you want to play along with the examples, in a tmp directory create the following files in each of the following subdirectories.

Tip Use the touch command to create the files. 
 
Files
MybashScript.sh mysource.c MySource.c Source.c
Subdirectories
backup 
backup1 
backup1/backup1a

When you are dome it should look like this

$ ls -R 
.: 
backup  backup1  MybashScript.sh  mysource.c  MySource.c  Source.c 
 
./backup: 
MybashScript.sh  mysource.c  MySource.c  Source.c 
 
./backup1: 
backup1a  MybashScript.sh  mysource.c  MySource.c  Source.c 
 
./backup1/backup1a: 
MybashScript.sh  mysource.c  MySource.c  Source.c

Find Files Using -name

As mentioned above the simplest way to find file is to use the -name option. Using the example setup
we can search for MySource.c.

$ find -name MySource.c 
./MySource.c 
./backup/MySource.c 
./backup1/MySource.c 
./backup1/backup1a/MySource.c

Finding files with a pattern

If you want to use the normal shell patterns such as '?', '*' or even '[asdf]' then you need to
put the pattern in single quotes to stop the shell from expanding them first. here is an example.

$ find -iname '*sh' 
./backup/MybashScript.sh 
./MybashScript.sh 
./backup1/MybashScript.sh 
./backup1/backup1a/MybashScript.sh

Find Files Using -iname but Ignoring Case

Here we use the -iname option so that find ignores the case of the name we enter.

$ find -iname MySource.c 
./MySource.c 
./mysource.c 
./backup/MySource.c 
./backup/mysource.c 
./backup1/MySource.c 
./backup1/mysource.c 
./backup1/backup1a/MySource.c 
./backup1/backup1a/mysource.c

Limiting the depth that find searches down a directory tree.

Using the same find as above we add the -maxdepth option and limit it to 2 subdirectories

# find -maxdepth 2 -name MySource.c  
./MySource.c 
./backup/MySource.c 
./backup1/MySource.c

Find the file between sub-directory level 2 and 4.

# find -mindepth 2 -maxdepth 3 -name MySource.c
./MySource.c
./mysource.c
./backup/MySource.c
./backup/mysource.c
./backup1/MySource.c
./backup1/mysource.c

Now for the good stuff with find.

We have already seen we can find files with specific names or patterns and limit the
sub-directory level we not only start at but how deep we go. Now having found the file we
can do stuff with it or to it. Cool or what!

Say we want to find all the *.c files and then calculate their md5 checksums. This could
be some source code for a new tool you are compiling and need to verify that what you
downloaded is what the developer posted. We tell find to run or execute the command with
the -exec option and we also tell find that the command we want to run passing the
filename with the special token '{}' and end the command that is to be run by find
with '\;'.

# find -name '*.c' -exec md5sum {} \; 
p$ find -name '*.c' -exec md5sum {} \; 
d41d8cd98f00b204e9800998ecf8427e  ./MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./Source.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup/MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup/mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup/Source.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/Source.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/backup1a/MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/backup1a/mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/backup1a/Source.c

Specifing names we do NOT want to match.

Using the example above but this time we want all '.c' files but not those that are called
'Source.c'

$ find -name '*.c' -not -name 'Source*' -exec md5sum {} \; 
d41d8cd98f00b204e9800998ecf8427e  ./MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup/MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup/mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/mysource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/backup1a/MySource.c 
d41d8cd98f00b204e9800998ecf8427e  ./backup1/backup1a/mysource.c

See how easy it is to build up the command but adding options.

These examples can get you out of trouble.

Say "someone" has been silly and created a file with a strange or awkward name. Such as
it has a space at the end of the filename of contains characters that are normally used
as patterns. renameing them or deleting them can be a problem. Find to the rescue. We can
use the files inode value to search with find and then use -exec to manipulate the
filename as required.

We need a few of example files, we shall use the following:

More test files
testfile "testfile " 'MybashProgra?.sh'

Note that there is a space at the end of the second filename, this means that when you
use 'ls' to see the files thay appear to have the same file name. You can use touch
to create the example files, put the strangely named files in quotes.

View the files with the ls command forcing the output into one column;

$ ls -1 
testfile 
testfile

You should see two filenames that look the same, but you also know that cannot be true.
We can use the -name and the -not -name combinastion to find the right file and rename it.

$ find -name 'testfile*' -not -name testfile -exec mv {} old_testfile \;

Now have a look and it's sorted out with the filename that did have the space at the end
now renamed to old_testfile

ls -1 
testfile 
old_testfile

To rename the remaining strangly name file we will use its inode to tell find which file
to rename. If we use the name itself 'MybashProgra?.sh' we get an error from ls saying
that the destination is not a directory. That is because there are two files that match
'MybashProgra?.sh'. To find which file we want to rename we use its inode. To find the
inode of a file we use ls again as below.

ls -1i 
5128944 MybashScript.sh 
5129074 MybashProgra?.sh

Now we can plug in the inode to finds -inum option and rename it as we like.

find -inum 5129074 -exec mv {} new_MybashScript.sh \;
ls 
MybashScript.sh 
new_MybashScript.sh 

Find files based on their File type or permissions

To find files by thier type use the -type option and then the type required

Common search types will be

  • d directory
  • p named pipe (FIFO)
  • f regular file
  • l symbolic link, there are some exceptions to this

So to earch for the directories in our example use the following.

$ find  -type d 

./backup 
./backup1 
./backup1/backup1a

To search and select based on permissions use the -perm option. This one gets complex
rather quickly, so I'm only mentioning the bascis here.

If you want to search for files that have exactly the permissions wherethe owner and
the group have both read and write but the world only has read access use this.

$ find . -perm 664

It is more likely that you want to find files wherethe permissions are at least like
those above. But you also want those that have execute permission too. The different
is that there is a '-' in front of the permissions.

$ find . -perm -664

You can also use the symbolic options to represent the permissions so ther two
example above would become,

find -perm  u=rw,g=rw 
find -perm  -u=rw,g=rw 
 

Finding Empty files

These files are usually lock-files and place holders created by other applications or
the test files from examples on blogs.

$ find -empty

Finding the big files on your system

Find even has an option to let you find files bigger or smaller than some size that you enter.

$ find ~ -size  128M       Exact size match    
$ find ~ -size +128M       greater than this 
$ find ~ -size -128M       less than this 

The 'M' in the examples above means Megabytes the other type it understands are

  • 'b' for 512-byte blocks (this is the default if no suffix is used)
  • 'c' for bytes
  • 'w' for two-byte words
  • 'k' for Kilobytes (units of 1024 bytes)
  • 'M' for Megabytes (units of 1048576 bytes)
  • 'G' for Gigabytes (units of 1073741824 bytes)

No feedback yet

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
PoorExcellent
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
What can birds and aeroplanes both do?
antispam test