Finding Stuff

finding files on your *nix system

by Mike Peters, February 2004

New users to Linux are often lost as to where they can find files. This article will take you through the various methods you can use to find the files you want. It will show how to search for files according to their name, permissions, size and other criterea.

The Linux filesystem

The first thing you should be aware of is the lay out of a typical Linux installation. I'm not go into great detail about the Linux filesystem, just enough to give you a rough idea of what you can expect to find where. Knowing that can help you narrow down your search considerably. Let's look at the / (root) filesystem of a typical setup:

mike@home:~$ ls
/bin
/boot
/dev
/etc
/home
/lib
/mnt
/opt
/proc
/root
/sbin
/tmp
/usr
/var

So, what's in these directories?

/bin - is where you can find essential executables which go to make up the Linux core, such as ls, mv, cp and mount.

/boot - is where you find the files needed to boot your distro, such as System.map and the kernel, although not in all distros.

/dev - is where you'll find all your devices.

/etc - is where most applications put their configuration files.

/home - users personal directories and files.

/lib - essential system libraries. Of special note is /lib/modules/KERNEL_VERSION where you can find all your kernel modules.

/mnt - is where removable devices are mounted such as floppies, cdroms, zip drives etc.

/opt - it depends on your distro or personal preference certain user applications may be installed here. Some distros install KDE and GNOME here.

/proc - information about running processes can be found here. Lots of system information can be gleaned from /proc.

/root - root's personal files.

/sbin - system executables such as insmod, fsck, ifconfig.

/tmp - temporary directory used by some applications to cache files or keep run time information.

/usr - applications not part of the Linux core are installed under /usr. If you look under /usr, you'll see a structure which is very similar to the root filesystem. Executables and system executables which make up your distro are found in /usr/bin and /usr/sbin respectively. Application documentation is found in /usr/doc, libraries are found in /usr/lib and XFree's files can be found uder /usr/X11 or /usr/X11R6. Header files, needed to install many applications from source are generally found in /usr/include. Shared application files, such as themes and data files are found in /usr/share. Applications which are not part of your official distro are generally installed in /usr/local. If you look under /usr/local, you'll find something which looks very similar to /usr (are you seeing the pattern yet?). One thing of note, configuration files of applications installed in /usr or /usr/local are usually, but not always, installed in /etc, as opposed to /usr/etc or /usr/local/etc.

/var - is where you'll find system logs, mail and print queues and databases (such as MySQL).

ls - the first port of call

ls [options] [file...]
dir [file...]
vdir [file...]

POSIX options: [-CFRacdilqrtu1] [--]

GNU options (shortest form): [-1abcdfghiklmnopqrstuvwx- ABCDFGHLNQRSUX] [-w cols] [-T cols] [-I pattern] [--full-time] [--show-control-chars] [--block-size=size] [--format={long,verbose,commas,across,vertical,single-col- umn}] [--sort={none,time,size,extension}] [--time={atime,access,use,ctime,status}] [--color[={none,auto,always}]] [--help] [--version] [--]

If you have an idea of which directory a file is in, the easiest way to find files is using ls. 'ls' on its own lists all of the files in the current directory. 'ls /some/directory' will list the files in /some/directory. If you want to see the hidden files in a directory use the -a option and if you want to see extended details about files in a directory use -l. For example to show all files and directories in /home/mike use:

mike@home:~$ ls -la /home/mike

Remember, you can use wildcards with ls too. To show all the files in /home/mike with a .html extension:

mike@home:~$ ls /home/mike/*.html

You can use a ? to indicate a single character, so:

mike@home:~$ ls /home/mike/?og.txt

will list the files dog.txt, fog.txt and bog.txt but not frog.txt. Whereas:

mike@home:~$ ls /home/mike/??og.txt

will only list frog.txt. You can also use [] to specify a range. For example:

mike@home:~$ ls /home/mike/[a-d]og.txt

will list files dog.txt and bog.txt but not fog.txt or frog.txt. This is especially useful for files with dates in the name. Say you have a directory of backup files called yyyymmdd_bak.tar.gz (such as 20030425_bak.tar.gz), you can list all files dated between March and August 2003 using something like:

mike@home:~$ ls /backups/20030[3-8]*_bak*

If you want to see only the directories present you need the -d option but beware:

mike@home:~$ ls -d /home/mike/

will only output /home/mike, which can be useful when used with the -l option to see a particular directories details, however, if you want to list all of the directories under /home/mike you need to use:

mike@home:~$ ls -d /home/mike/*/

To see only files, no directories, it's a little more involved:

mike@home:~$ ls -l /home/mike/ | grep -v "^d"

if you only want to see executable files in a directory, use:

mike@home:~$ ls -lF /home/mike/ | grep "\*$"

and finally to see only links you could do:

mike@home:~$ ls -l /home/mike/ | grep "^l"

Finding installed binaries

which [options] [--] programname [...]

In order to find a binary which has been installed in your $PATH, you can use 'which program':

mike@home:~$ which gvim
/usr/local/bin/gvim

which will only find files which you have the permission to execute and are in your $PATH. When given no options, which will only report the first executable found, ie the one which would be executed if you just type the command without the path. Use -a to show all matching executables.

whereis [ -bmsu ] [ -BMS directory... -f ] filename ...

whereis will show you the location of an executable, its related source files, libraries and documentation, providing the executable is installed in a 'standard' location.

mike@home:~$ whereis sylpheed
sylpheed: /usr/bin/sylpheed /usr/lib/sylpheed /usr/local/lib/sylpheed /usr/include/sylpheed /usr/share/sylpheed /usr/man/man1/sylpheed.1 /usr/share/man/man1/sylpheed.1

If you only wish to see the location of documentation use the -m option, -b will show only the binaries and -s will show only the sources.

Locate

slocate [-qi] [-d ] [--database=]
slocate [-i] [-r ] [--regexp=]
slocate [-qv] [-o ] [--output=]
slocate [-e ] [-f ] <[-l ] [-c] <[-U ] [-u]>
slocate [-Vh] [--version] [--help]

locate (or in the case of many distros, slocate), is a search utility which should be present in most if not all Linux distros. It indexes all of the files on your system, providing a fast way of searching for files. If you are using slocate as opposed to the older locate, file permissions are also stored thereby preventing users from seeing files to which they would not normally have access. The advantage of a facility like locate over a command like find (see below), which do a full search of the file system, is that it is much quicker.

mike@home:~$ locate unistd

warning: locate: warning: database /var/lib/slocate/slocate.db' is more than 8 days old
/usr/src/linux-2.4.23/include/linux/unistd.h
/usr/src/linux-2.4.23/include/asm-sh/unistd.h
/usr/src/linux-2.4.23/include/asm-mips64/unistd.h
/usr/src/linux-2.4.23/include/asm-parisc/unistd.h
/usr/src/linux-2.4.23/include/asm-x86_64/unistd.h
/usr/src/linux-2.4.23/include/asm-x86_64/ia32_unistd.h

[snip]

/usr/src/linux-2.4.24/include/asm-arm/unistd.h
/usr/src/linux-2.4.24/include/asm-ppc/unistd.h
/usr/src/linux-2.4.24/include/asm-sparc64/unistd.h
/usr/share/texmf/include/kpathsea/c-unistd.h
/usr/include/sys/unistd.h
/usr/include/unistd.h
/usr/include/asm-i386/unistd.h

There are a couple of disadvantages however. As you can see in the above example, we were warned that our database is over 8 days old. Locate will only find files which have been added to the database. We can get round this problem by making sure we regularly update our database. This can be done by running 'updatedb' on a regular bases, such as from a cron job.

The second restriction of locate is that we can only perform basic searches for files by name. If we want to do a more detailed search we need to use 'find'.

Find - the mother of searches

find [path...] [expression]

find will search the directory tree for files according to the rules given. find has the disadvantage that it is much slower than locate but it is a much more comprehensive utility. Most users don't go beyond the basic capabilities of find, but there are a whole host of options availlable. I wont go into all of the options here but just enough to give you an idea of the possibilities available.

'find' on its own will print a list of all files in the current directory. If you want to start searching in a particular directory you can specify the starting directory.

mike@home:~$ find /usr/include -name unistd.h -print

/usr/include/sys/unistd.h
/usr/include/unistd.h
find: /usr/include/Hermes: Permission denied
/usr/include/asm-i386/unistd.h
find: /usr/include/ptlib/CVS: Permission denied
find: /usr/include/ptlib/unix/CVS: Permission denied
find: /usr/include/ptlib/unix/ptlib/CVS: Permission denied
find: /usr/include/ptclib/CVS: Permission denied
find: /usr/include/openh323/CVS: Permission denied

There are a few things to note here. We specify the search path directly after 'find', this is followed by the expression we are searching for and what we want to do with it. As you might expect -name tells find to search for files with the name 'unistd.h' (we could have used -iname to specify a case insensitive search) and -print says to print the result to our console. Actually we could have left off the -print option as this is the default. We needed to give the full name of the file, as, unlike locate, find searches for the exact expression. If we don't know the exact name of the file it's better to use a wildcard expresion. We can also suppress the 'Permission denied' messages by directing error messages to /dev/null using 2>/dev/null (Note: this is not specific to find and can be applied to any command):

mike@home:~$ find /usr/include -iname 'unistd*' 2>/dev/null
/usr/include/sys/unistd.h
/usr/include/unistd.h
/usr/include/asm-i386/unistd.h

find can also be used to search for files according to their last access or modification dates.

Find php files in /var/www/html which have been accessed in the last 10 minutes:

mike@home:~$ find /var/www/html -iname '*.php' -amin -10

Same but modified in the last 10 minutes:

mike@home:~$ find /var/www/html -iname '*.php' -mmin -10

To do the same thing using hours rather than minutes you would use:

mike@home:~$ find /var/www/html -iname '*.php' -atime -10
mike@home:~$ find /var/www/html -iname '*.php' -mtime -10

Note here the use of -10 rather than 10. 10 would have searched for files modified or accessed exactly 10 hours/minutes ago. You could also have used +10 to search for files modified or accessed more than 10 hours/minutes ago.

If you want to search for files according to their size, find can do that too:

mike@home:~$ find /home/downloads -size +1000k
mike@home:~$ find /home/downloads -size -1000k

As you've probably worked out, these commands find files of size more or less than 1000k respectively.

Another useful feature of find is to search for files belonging to certain groups or users:

mike@home:~$ find /var/www/html/ -group nobody
mike@home:~$ find /var/www/html/ -user nobody

These, and in fact all, find commands can be combined using conditional statements, for example:

mike@home:~$ find /var/www/html/ ! -group nobody

will find files in /var/www/html/ which don't belong to the nobody group. Expanding on this:

mike@home:~$ find /var/www/html/ ! -group nobody -a ! -user nobody

will find files which are not in group nobody and are not owned by user nobody. As you've guessed, ! is equivalent to not and -a equals and (you can use -and also). You can use -o to make or statements such as:

mike@home:~$ find /var/www/html/ ! -group nobody -o ! -user nobody

which will find files not in group nobody or owned by nobody. As I stated earlier, this doesn't just work for -group and -user, you can mix and match options such as:

mike@home:~$ find /home/music/ -iname "*.mp3" -a -user mike -a -size +10000k

to find mp3's in /home/music which belong to user mike and are over 10MB in size.

What if we want to find files which have certain permissions, such as world readable or writable files? Well, find can also be used for this with the -perm option. There are basically 3 different ways to use -perm, the first is -perm mode which will find all files which have there permisions set exactly to mode, eg:

mike@home:~$ find /etc -perm 755

secondly -perm -mode finds files with all of thier bits set to mode, eg:

mike@home:~$ find /etc -perm -7

is the same as -perm 777. Lastly -perm +mode will find files where one or more of their bits are set to mode, eg:

mike@home:~$ find /etc -perm +7

If you wish to find all world writable files on your system you would therefore use:

mike@home:~$ find / -perm -2

but this has a problem in that it will also list symbolic links which have permissions of lrwxrwxrwx. To prevent this we can use the -type option:

mike@home:~$ find / -perm -2 ! -type l

this exclude files of type l, which stands for link. Type takes several options the most useful of which are f for file, d for directory and l for links.

We can also use symbolic permission modes with -perm. The following example will find all set-user-ID and set-group-ID files:

mike@home:~$ find / -type f -perm -u+s -o -perm -g+s

It can also be usefull to find files on a machine which have no valid user or don't belong to a valid group. The -nouser and -nogroup options do just this:

mike@home:~$ find / -nouser -o -nogroup

Searching on / can take an extremely long time and therefore we often don't want to descend onto mounted files systems, we can restrict the search to the current filesytem by using the -xdev option.

mike@home:~$ find / -nouser -o -nogroup -xdev

The final feature of find which I want to go into is the -exec option. This option will execute a command on the result of the find command. So, for example, you could us ls -lh to list the files found rather than the standard output:

mike@home:~$ find /home/music/ -iname "*.mp3" -a -user mike -a -size +10000k -exec ls -lh {} \;

Some other examples:

mike@home:~$ find /home/music/ -iname "*dj*food*.mp3" -exec mpg123 {} \;
mike@home:~$ find /var/www/html -iname "*~" -exec rm {} \;
mike@home:~$ find /var/www/html -iname "*.php" -exec grep -i foobar {} \;

{} indicates to find that it should insert the name of each file returned here and \; indicates the end of the command.

I haven't covered all of the options available to find in this article, but, I hope that at least I have given you enough to show you just how powerful a utility find can be. Check the man pages if you want to see all of the options available.

Conclusion

Hopefully you have enough information now to find any file on your system quickly and easily. As you can see, on any *nix system there are many ways to find the file you want, it's just a case of using the right tool for the job.





Save This Page
mikepeters See mikepeters' photos on flickr
Created with Vim   Graphics by GIMP