Winter 2019 - January to April 2019 - Updated 2018-10-10 00:39 EDT
How can we look for a file name?
What if we don’t know which directory that file is located in?
Can we start afgrepat the root and ask thefgrepcommand to look in all subdirectories?
People confuse fgrep, which looks for text inside files (and
doesn’t look at the file names), with find, which finds files
by name (and doesn’t look inside the files).
The fgrep (and grep and egrep) commands look for patterns or text
inside files whose names you already know. They aren’t directly useful
for finding and generating the names of those pathnames. (To use
fgrep to find the full name of a pathname, you would first have to use
some other command to generate a list of all pathnames and feed that to
fgrep in a pipeline as standard input – see the example below.)
You can tell fgrep to search the contents of an entire directory tree of
files by turning on the fgrep “recursive” option; but, that won’t help
you find the name of a pathname in that directory. The fgrep command
searches content inside files, it doesn’t find the names of files.
To find pathnames by name you can use the find command. If the pathname
has existed for some time and is saved in the right database, you might be
able to use the faster locate or slocate commands to search by name.
To find pathnames by anything other than name, e.g. size, or owner, or
modify date (etc.), use the find command with the right expression.
See below.
find commandIndexThe Usage line for find given below is abbreviated from man find:
Usage: find [options...] [startdir...] [expression]
The [startdir...] is an optional list of starting directories in which
find will do the search, instead of using the current directory.
You rarely need to use any options, so the first thing following the
find command name is usually the one directory or list of directories
in which to look. The current directory is the default.
The find command has its own huge set of expressions for finding
pathnames precisely and efficiently. The expressions follow the starting
directories on the command line.
Below are five important uses of find, each explained in detail.
You can find:
basename patternuserid1. find [startdir...] -print
2. find [startdir...] -name 'basename' -print
3. find [startdir...] -user 'userid' -print
4. find [startdir...] -mtime -30 -print
5. find [startdir...] -size +100M -print
The optional startdir... list in which to search comes first, followed
by the optional expression that says what to find. If you don’t
specify any startdir, find uses . (the current directory).
The optional expression must follow the starting directories.
The expression limits the pathnames that are found or changes the
output format. It consists of keywords, each preceded by dashes and
usually followed by some argument, e.g.
-name 'basename', -size +100M, -print, or -ls.
Without any expression, find finds all pathnames.
With modern versions of find, you can omit the -print keyword;
it’s the default behaviour.
The -name expression allows you to give a matching pattern that
is the basename, found in any directory, starting from each of
the starting_directories. The basename patterns can include
shell-GLOB-style path metacharacters such as * and ?, and the
patterns must be quoted to protect them from GLOB expansion by
the shell, e.g. find -name '*.txt'
The -user expression allows you to give a userid that must be
the owner of the pathnames found, e.g. find -user 'root'
The -mtime expression allows you to give a modify time expression.
Using +10 means “older than 10 days” and -5 means “younger than
5 days, etc., e.g. find -mtime +365
The -size expression allows you give a size number, to match
pathnames based on their rounded-up size. The size can have various
size multipliers such as M for “MegaByte”, and the actual size of
the file is rounded up to that multiplier before comparing. A leading
minus on the number means “less than” and a leading plus on the
number means “greater than” the given rounded size. The expression
-size -100k means “rounded-up size less than 100 kilobytes”.
Using -size 0 is a useful expression, to find pathnames
that are empty (zero size), and -size +0 finds pathnames
that are not empty (size greater than zero).
Note that the size rounding means that -size -1M only matches
zero-size files (because even a one-byte file rounds up to 1M and
doesn’t match)! If you really want to see all files smaller than 1M,
you have to avoid the rounding and use 1024x1024 characters: -1048576c
See the man page for more help, and search the net for examples.
For example, the -type f and -type d expressions are
useful for finding only file names or only directory names:
$ find . -type f
$ find . -type d
The find command has expressions that can find pathnames based on
any combination of any of the attributes you see in the output of
ls -dils.
You can use multiple expressions, and the pathnames found must meet all the conditions of the expressions used, e.g.
$ find /bin /etc/ -name '*word' -user 'root' -size +1k
With more syntax, you can also have find show pathnames that match
one expression or another expression, or any Boolean combination
of expressions. See the man page.
-lsIndexThe find command can output detailed attribute information about the
pathnames it displays using the -ls expression instead of using the
default -print expression:
$ find . -ls
The detailed output is similar to the output you would get if you typed
ls -dils for the displayed names:
$ find /etc/passwd -ls
2101779 4 -rw-r--r-- 1 root root 2879 Oct 4 10:59 /etc/passwd
$ ls -dils /etc/passwd
2101779 4 -rw-r--r-- 1 root root 2879 Oct 4 10:59 /etc/passwd
This is the option to use if you want to display attribute information about the pathnames as well as the names.
find, including World-WritableIndexYou can try these examples. Some will produce error messages as
well as pathnames, since you don’t have permission to search all the
system directories. Ignore the errors (or redirect standard error to
/dev/null); look at the results:
$ find /bin -name '*sh'
/bin/bash
/bin/dash
/bin/static-sh
/bin/sh
/bin/rbas
$ find /bin -type f -size +500k
/bin/bash
/bin/busybox
$ find /tmp -maxdepth 1 -user root -type d
/tmp
/tmp/.X11-unix
/tmp/.ICE-unix
/tmp/ssh-mZgPJ11302
In all the examples below, in modern versions of find, you can leave
off the default -print action:
find . -print or find . or simply find
find)find /etc -name 'passwd' -print
/etc ending with basename passwdfind /etc /lib -name '*.conf' -print
/etc or /lib ending in .conffind /bin -name '?ash' -print
/bin with four-character basenames ending in ashfind /var/mail -user root -print
/var/mail owned by the root userfind "$HOME" -mtime -30 -print
find . -type f -print
find . -type d -print
find . -size -100M -print
find . -size +1k -print
find . ! -type l -perm /o+w -ls
! means not symlinks)find /bin /etc/ -name '*word' -user 'root' -size +1k -ls
find expressions and only pathnames
that meet all the criteria will be listedIf you use a pattern in the
-nameexpression, remember to quote the pattern to protect any GLOB pattern characters from expansion by the shell! The characters need to be quoted to be GLOB-expanded byfind, not by the shell.
fgrep on the output of findIndexWhile find has powerful pattern matching expressions, some people
prefer to pipe the pathname output of find into one of the grep
family of text searching programs because they better know how to use
grep regular expression pattern matching.
You can generate a list of all pathnames under a given directory using
the find command and then use grep on that piped output, e.g.
$ find
... all pathnames under the current directory list here ...
$ find "$HOME"
... all pathnames under your HOME directory list here ...
$ find /bin | wc -l # count pathnames under /bin
107
$ find /bin | fgrep 'sh' # only pathnames containing 'sh'
/bin/bash
/bin/dash
/bin/static-sh
/bin/sh
/bin/rbash
/bin/sh.distrib
$ find /bin | grep 'sh$' # only pathnames ending in 'sh'
/bin/bash
/bin/dash
/bin/static-sh
/bin/sh
/bin/rbash
The
grepprogram uses a pattern matching language similar to GLOB patterns but more powerful called Regular Expressions. Don’t usegrepto look for text until you become familiar with this pattern matching language; use the saferfgrepcommand instead.
find on the ROOT directoryIndexYes, you can do find / (find, starting at the top-most ROOT
directory) and it will generate a list of all the pathnames on the whole
machine that you have permissions to see – tens of thousands of them.
This will take a long time. (You will also see many error messages
about permissions, since your userid does not have permissions to look
in every directory on the whole system.) Don’t run find / on
a shared computer unless you really have to. (But feel free to try it
on your own machine!)
locate or slocate commandsIndexMany Unix systems run a weekly or nightly find / late at
night and save the results in a small database. The locate or
slocate commands can quickly search that saved database for you
much faster than find, even using a file GLOB pattern, e.g.
$ locate passwd | less
... see all the names containing the string "passwd" here ...
$ locate '/etc/*passwd*'
/etc/passwd
/etc/passwd-
/etc/cron.daily/passwd
/etc/dovecot/conf.d/auth-passwdfile.conf.ext
/etc/init/passwd.conf
/etc/init.d/passwd
/etc/pam.d/chpasswd
/etc/pam.d/passwd
/etc/security/opasswd
Note the use of quotes to stop the shell from interpreting the GLOB
pattern. (We want the locate command to process the GLOB pattern
against the pathnames in the database; we do not want the shell to
process the GLOB pattern against current pathnames in the file system
before it calls the locate command.)
If you are looking for a pathname that has been around for a while and
is entered into the database, the locate database lookup is much,
much faster than a huge ROOT find /. If you are looking for
a new pathname that isn’t in the locate database yet, only find will
find it for you.