Saturday, July 07, 2007

Using the Common UNIX Find Command

One of the most useful utilities in the UNIX systems resources directory is the find command. System administrators use this powerful utility frequently. Here are a few common tasks performed by the ubiquitous find command. I'll add more as time goes on.

# cd /export/home/esofthub

Find a file or directory
# find . -name TEMP -print
or
# find . -name TEMP -exec echo {} \;

Find core files in this directory tree and remove them
# find . -name "core" -exec rm -f {} \;

Find junk directories and remove their contents recursively
# find . -name "junk" -exec rm -rf {} \;

Find files not starting with "junk" OR not ending with "log"
# find . ! \( -name "junk*" -o -name "*log" \) -print

Find a pattern in a file using the recursive grep (ignore case)
# find . -type f | xargs grep -i MYPATTERN
# find . -name '*.sh' -exec grep -i MYPATTERN {} \;

Find files modified in the past 7 days
# find . -mtime -7 -type f

Find files owned by a particular user
# find . -user esofthub

Find all your writable directories and list them
# find . -perm -0777 -type d -ls
or
# find . -type d -perm 777 -print

Find all your writable files and list them
# find . -perm -0777 -type f -ls
or
#find . -type f -perm 777 -print

Find large file sizes and list them or output to file
# find . -type f -size +1000 -ls
or
# find . -type f -size +1000 -print
# find . -type f -size +2000K | tee filename

Find how many directories are in a path (counts current directory)
# find . -type d -exec basename {} \; | wc -l
53

Find how many files are in a path
# find . -type f -exec basename {} \; | wc -l
120

Find all my pipe files and change their permissions to all writable
# find . -name "pipe*" -exec chmod 666 {} \;

Find files that were modified 7 days ago and archive
# find . -type f -mtime 7 | xargs tar -cvf `date '+%d%m%Y'_archive.tar`

Find files that were modified more than 7 days ago and archive
# find . -type f -mtime +7 | xargs tar -cvf `date '+%d%m%Y'_archive.tar`

Find files that were modified less than 7 days ago and archive
# find . -type f -mtime -7 | xargs tar -cvf `date '+%d%m%Y'_archive.tar`

Find files that were modified more than 7 days ago but less than 14 days ago and archive
# find . -type f -mtime +7 -mtime -14 | xargs tar -cvf `date '+%d%m%Y'_archive.tar`

Find files in two different directories having the "test" string and list them
# find esofthub esoft -name "*test*" -type f -ls

Find files in two different directories having the "test" string and list them
# find esofthub esoft -name "*test*" -type f -ls

Find files in two different directories having the "test" string and count them
# find esofthub esoft -name "*test*" -type f -ls | wc -l
12

Find files and directories newer than CompareFile
# find . -newer CompareFile -print

Find files and directories older than CompareFile
# find . ! -newer CompareFile -print

Find files and directories but don't traverse a particular directory
# find . -name RAID -prune -o -print

Find all the files in the current directory
# find * -type f -print -o -type d -prune

Find files associated with an inode
# find . -inum 968746 -print
# find . -inum 968746 -exec ls -l {} \;

Find an inode and remove
# find . -inum 968746 -exec rm -i {} \;


15 comments:

ux-admin said...

Avoid using "-exec {}", as it will fork a child process for every file, wasting memory and CPU in the process. Use `xargs`, which will celeverly fit as many arguments as possible to feed to a command, and split up the number of arguments into chunks as necessary:

find . -depth -name "blabla*" -type f | xargs rm -f

Also, be as precise as possible when searching for files, as this directly affects how long one has to wait for results to come back. Most of the stuff actually only manipulates the parser rather than what is actually being searched for, but even there, we can squeeze some performance gains, for example:

- use "-depth" when looking for ordinary files and symollic links, as "-depth" will show them before directories

- use "-depth -type f" when looking for ordinary file(s), as this speeds up the parsing and the search significantly:

find . -depth -type f -print | ...

- use "-mount" as the first argument when you know that you only want to search the current filesystem, and

- use "-local" when you want to filter out the results from remote filesystems.

Note that "-local" won't actually cause `find` not to search remote file systems -- this is one of the options that affects parsing of the results, not the actual process of locating files; for not spanning remote filesystems, use "-mount" instead:

find / -mount -depth \( -type f -o -type s) -name "blabla" -print ...

ux-admin said...

Oops, the last command should have been

find / -mount -depth \( -type f -o -type l \) -print ...

esofthub said...

ux-admin, as usual, that was a great comment. Thanks.

So when are you going to do a guest post on My SysAd Blog? :) Roy

UX-admin said...

When two things happen:

- you tell me what I should write about

- I can squeeze enough time for more than just dropping a few quick notes.

esofthub said...

ux-admin, I'm on the road right now. Please send me an email at info@esofthub.com. I'll get back to you ASAP. Thanks Roy

Josh said...

From the find(1) man page:

-exec command {} +
This variant of the -exec option runs the specified command on the selected files, but the command line is
built by appending each selected file name at the end; the total number of invocations of the command will
be much less than the number of matched files. The command line is built in much the same way that xargs
builds its command lines. Only one instance of â{}â is allowed within the command. The command is exeâ
cuted in the starting directory.

Anonymous said...

the recursive finds were useful

UX-admin said...

" Josh said...

From the find(1) man page:

-exec command {} +
This variant of the -exec option runs the specified command on the selected files, but the command line is
built by appending each selected file name at the end; the total number of invocations of the command will
be much less than the number of matched files. The command line is built in much the same way that xargs
builds its command lines. Only one instance of â{}â is allowed within the command. The command is exeâ
cuted in the starting directory."

Apparently, "-exec" seems to be implementation specific, which is another good reason to avoid using it, since it means that performance factor will differ from implementation to implementation.

My point is, by using `xargs`, one assures that the script / command will remain behaving the same across different UNIX(R) and UNIX(R) like operating systems.

If you had to choose between convenience and portability+consistency, which one would you choose?

arne said...

instead of using
find ./ -name blah
I find it better to use the case-insentive form of -name, -iname:
find ./ -iname blah

Anonymous said...

You have to be careful when you remove things.
You say remove files which name is core, but lacks the "-type f" option:
find . -name "core" -exec rm -f {} \;
The same for the example with directories named "junk". Your command would delete any type of files called junk (files, directories, links, pipes...)

I did not know about "-mount", I've always used "-xdev".
Another nice feature, at least in linux find, is the "-exec {} \+", which will fork only once.

Nice good article, and also the comments!

raleighadmin said...

#
# a non-recursive file listing
#
find /var/spool/mqueue/* -type d -prune -o -type f -print

savithrb said...

I was looking for non-reccursive find. this doesn't help. it's still doing reccursuive search

Anonymous said...

Hi,

This Page is awesome.I found all the details that i needed for find

buddy said...

Nice article. here is my way of using find command in Unix hope this would be useful for you.

Gamer said...

Good article on Find Command