HP-UX Admin Man: The Search Continues

Last month we talked about the line syntax of the find command and used a few of the 'what to look for' qualifier options. This month we look for many more of the qualifier options including qualifiers with arguments.

As a review,

find ~ -name '*test' -print

will list (or print) all object names (files or directories or ...) in my home directory ( ~ ) whose name ends with "test". Note that the -name option acts to match a pattern (*test) against the name of the object. There is a similar qualifier that matches against the pathname of the object find is checking, instead of against only the name (basename) of the object.

For example, this command:

find ~ -name '*top' -print

results in the following output on my system:

/disc/users/fred/archive/desktop
/disc/users/fred/desktop

because those were the only two objects with names that ended in "top". Changing the qualifier option from -name to -path:

find ~ -path '*top' -print

results in the same output. This is actually an improper use of the -name option. Since the option is used to match against the pathname, rather than the object name, you must specify a pattern that matches the entire pathname (if you don't, find seems to treat -path the same as -name). A proper pattern typically starts with '*/' and ends with '/*', and can use any of the standard filename wildcard characters. For example:

find ~ -path '*/*top/*' -print

would now list every name under any pathname that has a directory name ending in 'top' - for example: '/disc/users/fred/desktop/ hppro - would appear in the output, as well as every other object under the '/disc/users/fred/desktop' and '/disc/users/fred/archive/desktop' directories.

Next are a couple options that are primarily used by system administrators. If a file is restored from tape and it was owned by a user that is not valid for this system, it can cause numbers, instead of owner information, to appear in the output of the ls command. The following find command will list all such files on this system:

find / \( -nogroup -o -nouser \) -print

This command reads in ordinary English as: find and print the pathname for all files from the / level down, that either have no owner, or no group owner listed in the password database. I was surprised by how many it found on my system (120).

Numeric arguments

So far we have used the -name and -path options that required arguments. The next few options accept a numeric argument instead of a filename pattern. There are a couple issues with these numeric arguments that you must understand before using them. First of all, in the man pages they are usually listed as 'n'. For example, the -size qualifier is usually listed as '-size n'. Whenever you see the n, this means you can use a decimal integer numeric argument to the option. The trick is that find looks for an exact match to that number. For example:

find ~ -size 2 -type f -print

This looks for files that are exactly 1024 bytes in length. This could also be written as:

find ~ -size 1024c -type f -print

By default, the numeric argument to the size option means number of 512 byte blocks. If a 'c' follows the number (as in the second example), the number now means characters (bytes). If you prefix the number with a sign, this changes the meaning to 'less than' or 'greater than' this integer. For example, to look for small files in my home directory I might issue:

find ~ -size -1024c -type f -print

Note that this would find files that are 1023 bytes or less in size (not files that are exactly 1024 bytes).

Several other qualifier options take numeric arguments, such as:

-user n
-group n

These options take the numeric user or group ID number. Remember that they can be used with the logical operators to get 'ranges' of numbers. For example, if I wanted to list all objects owned by users whose UID numbers were between 1000 and 1600, this would work:

find / -user +999 -user -1601
-print

This takes advantage of the implied -a (and) operator between any two options.

find / \( \( -user +999 -user
-1601 \) -o -group 38 \) -
print

prints the pathname for objects owned by users with UIDs between 1000 and 1600, or those objects that have a group number (GID) of 38.

The -links n option is true if there are n hard links to an object being tested. The -inum n option can be used to look for files with a specific inode number.

Another way to search for objects would be based on time. This is among the most more common reasons for developing a list of pathnames. For example, the -atime n option determines if an object was last accessed in 'n' days.

find ~ -atime +179 -print

This command lists files that have not been accessed for over 179 days. Note that directories have the time accessed changed by the find command itself, so it is really only useful for files.

Some related options are -mtime n and -ctime n for comparing against time modified or changed respectively. The meaning of time modified is rather obvious: directory or file contents being changed. Change time of an object is updated whenever information stored in the inode structure is changed, such as permissions, ownership or size of the object. Developing a list based on modification time is often used for backup-type purposes, or to limit a find search only to files you have modified recently.

Pruning the list

You can usually qualify all the objects you want, a harder problem is to remove items you don't want from the list. Let's take an example:

find ~ -type f -atime +179 -print

This command builds a list of files in my home directory that have not been accessed in the last half year. Supposing my purpose for building this list is to move all those files into my 'archive' directory. The problem is that I want to put them into the existing '~/archive' directory. The command above also lists all files that are already in that directory. We could pipe the output through grep -v, but that would not work perfectly.

A good solution would be to use the -prune option of find. This option can be used to prevent find from searching in a particular directory tree.

find ~ -path '*/fred/archive/*'
-prune -o -type f -atime +179
-print

Now the list created will not contain anything under the 'archive' tree. Another similar option is -fstype. This option accepts some arguments that determine the filesystem type it will traverse. For example, you can prevent following links that point across NFS mount points with:

find / -fstype NFS -prune

Similarly, you could also have written:

find / -fsonly HFS

After all, this is UNIX, so there has to be more than one way to do something. Next month we will finish with the find command by looking at the ways that find allows us to have commands automatically executed using pathnames that find found as arguments.