What find Does
The find command walks a directory tree and, for each file it encounters, evaluates a series of expressions you supply. Each expression returns either true or false for that file. By default, find prints the path of every file for which the overall result is true.
An expression takes the form -something, usually followed by an argument. The expression is the test, the argument is what you’re testing for.
When you write several expressions one after another, find ANDs them together. A file must satisfy all of them to be selected.
find /data -type f -name “*.log”
This finds only plain files (-type f is true) and whose name ends in .log (-name “*.log” is true). If either test fails, the file is skipped.
Note that there are quotes around *.log. If there weren’t the shell would expand the *.log into a list of files, which would confuse the find utility, which expecting exactly one file specification. You could also quote the * with a backslash (\*) if you want to save a keystroke.
Combining Expressions
AND (default)
Placing two expressions in a row implies AND. Both must be true. You can actually have as many as you want and they’ll all be ANDed together. Although AND is implied, you can also specify it with -a if you think it improves readability. Newer versions of find support -and too.
find /home -user frank -size +10M
Finds files owned by frank and larger than 10 MB.
OR — -o
Use -o between expressions when either condition should match.
find /var -name “*.log” -o -name “*.tmp”
Finds files ending in .log or .tmp.
When mixing AND and OR, AND binds more tightly, just like multiplication before addition in arithmetic. Newer versions of find allow -or as well as -o.
Use parentheses (escaped from the shell) to make grouping explicit:
find /var \( -name “*.log” -o -name “*.tmp” \) -mtime +7
This finds .log or .tmp files that are also older than 7 days.
NOT — !
Place ! (or -not) before an expression to negate it. -not is sometimes more readable.
find /data -type f ! -name “*.bak”
Finds plain files whose name does not end in .bak.
Choosing the Starting Point
The first argument to find is always the directory to search from. find descends into sub-directories automatically. You can actually specify as many starting points as you like. They don’t look like expressions because they don’t begin with a -.
find / # searches everything (use with caution)
find . # searches from the current directory
find /var /home # searches both /var and -home
Common Expressions
-name and -iname
-name matches the filename (not the full path) against a shell-style pattern. The pattern must be quoted to stop the shell expanding it.
find /etc -name “*.conf”
-iname matches the filename but is case insensitive.
find /home -iname “readme*”
This matches README.txt, Readme.md, readme, and so on.
-type
Filters by file type. The most useful values on AIX are:
| Value | Meaning |
| f | Normal file |
| d | Directory |
| l | Symbolic link |
| b | Block device |
| c | Character device |
| p | Named pipe (FIFO) |
For example:
find /dev -type b
Find all block devices in /dev
Beware of not specifying a type, as you can get unexpected results with exec if you pass a directory to a utility when you thought it was getting just one file.
-mtime and -ctime
Both take a number of days.
-mtime n — the file’s modification time (data last written) is exactly n days ago.
-ctime n — the file’s change time (inode last changed — includes permission or ownership changes) is exactly n days ago. In other words, this is changes to the file’s metadata, not changes to its contents.
When using mtime or ctime you almost always use a + or – prefix:
| Prefix | Meaning |
| +n | More than n days ago |
| -n | Less than n days ago (i.e. within the last n days) |
| n | Exactly n days ago (not often very useful) |
find /logs -mtime +30 # not changed for over 30 days
find /tmp -ctime -1 # inode changed within the last day
Some versions of Unix, such as BSD, allow units other than days, as a suffix, such as s for seconds and h for hours. AIX may do so in the future, but not as of version 7.3.
-size
Matches on file size in blocks, and a block is 512 bytes.. As with the time expressions, other Unix systems allow a suffix, such as k for kilobytes, g for gigabytes, but as of AIX 7.3 this is not supported.
Again, + and – prefixes mean greater-than and less-than.
find /data -size +100 # files larger than 50K
find /tmp -size -2 # files smaller than 1K
-user and -group
Matches files owned by a specific user or group. You can use either the name or the numeric UID/GID.
find /home -user frank
find /projects -group dba
-perm
Matches on permission bits. The mode can be octal or symbolic.
find /bin -perm 4000 # files with the setuid bit set
find /tmp -perm 777 # files with exactly rwxrwxrwx
find /etc -perm 022 # files writable by group or other
Check the man page on the specific version of AIX you are using for symbolic representation as it has changed over time. It’s safer to stick with octal.
Finding Files with No Valid Owner: -nouser and -nogroup
find / -nouser
find / -nogroup
-nouser is true for any file whose numeric UID has no matching entry in /etc/passwd. -nogroup does the same against /etc/group.
These are useful after accounts are deleted — the files are left behind but owned by a UID that no longer maps to a name. On an AIX system using LDAP or NIS, the lookup is still done against the locally visible name database, so a file owned by a valid LDAP user will not be flagged unless that user is absent from the local resolution path.
What to Do With the Files Found
By default find simply prints each matching path. Several expressions change this behaviour.
The default action — prints the full path, one per line. You rarely need to write it explicitly.
find /home -name “core” -print
-ls
Produces output in the format of ls -dils for each matched file: inode number, size in blocks, permissions, link count, owner, group, size in bytes, modification time, and name. Much more informative than -print for diagnostic work.
find /var/log -size +50M -ls
-exec
Runs an arbitrary command for each matched file. The string {} is replaced by the file’s path (this is the only time I’m aware of {} being used as a placeholder in Unix). The command must be terminated by \;. In fact, find is looking to end -exec with a semicolon, but this character has a special meaning to the shell so it’s necessary to use a \ or quotes to allow find to see it.
find /tmp -mtime +7 -exec rm {} \;
Deletes every file in /tmp not touched for more than 7 days.
find /home -name “*.log” -exec gzip {} \;
Compresses each .log file found using gzip.
The {} placeholder can appear more than once in the command if needed.
Running a command on all results at once with +
Replacing \; with + causes find to batch the paths and pass as many as possible to a single invocation of the command — much more efficient for commands like rm or chmod:
find /tmp -mtime +7 -exec rm {} +
Practical Examples
List all files larger than 100 MB modified within the last 30 days
find / -type f -size +200000 -mtime -30 -ls
This breaks down as:
- -type f — regular files only (skip directories, devices, and links)
- -size + 200000 — larger than 100 MB (e.g. 200,000 512-byte blocks)
- -mtime -30 — data modified within the last 30 days
- -ls — show full details rather than just the path
Move those files to /problems
find / -type f -size +100M -mtime -30 -exec mv {} /problems/ \;
Find and remove core dumps older than 14 days
find / -name “core” -type f -mtime +14 -exec rm {} \;
Find setuid files not owned by root
find / -type f -perm -4000 ! -user root -ls
Find files owned by deleted accounts
find /home -nouser -ls
Summary of Expression Syntax
find <path> [expression]
Expression operators:
expr1 expr2 AND (both must be true)
expr1 -o expr2 OR (either must be true)
! expr NOT (negates the result)
\( expr \) Grouping to override precedence
Common tests:
-name pattern Filename matches shell pattern (case-sensitive)
-iname pattern Filename matches shell pattern (case-insensitive)
-type [fdlbcp] File type
-mtime [+/-]n Modification time in days
-ctime [+/-]n Inode change time in days
-size [+/-]n[cMG] File size
-user name|uid Owned by user
-group name|gid Owned by group
-perm [-/]mode Permission bits
-nouser UID not in /etc/passwd
-nogroup GID not in /etc/group
Common actions:
-print Print path (default)
-ls Print detailed listing
-exec cmd {} \; Run command once per file
-exec cmd {} + Run command with batched file list

