|
LDP Mirror
Forums RSS
Past club events:
UHACC @ Penguicon
LinuxFest 2004
SCO-B-Q
UHACC @ Flatcon
Club Pages:
ISU chapter: ISUnix
Member's Sites
Projects:
UHACC CVS
Club Documents:
Our Guiding Principles
UHACC Constitution
Operating Code
Membership App
AUP
|
UHACC 7 Nov 2001 - mongoose lectures on:
Using find
The find command is used to locate files on a UNIX or UNIX-like system.
Since UNIX treats everything as a file, it can be a useful tool for admins, programmers, and hobbyists alike.
To use find, think of what you are attempting to locate in terms of its attributes: permissions, ownership, type of file, time stamps, name, size, etc. Even an approximation can yield useful results when applied.
I will begin by addressing the most popular complaint about find:
"Ugh dude, find is farging slower than molasses in January!"
I hear that one a lot.
More often than not, I go on to listen to the person complain about how they were looking for some file and that they were waiting and waiting for it to parse through every file in every directory on the machine.
This tells me that they probably didn't invest much time into telling find about what it is they were searching for or where it might be (or might NOT be).
This is what I call the "shotgun approach" and my response to that is this: Of course it's slow!
You gave it hardly any info except a partial filename, and the scope is not even limited to any particular directory or directories.
So there it goes - hammering through every nook and cranny of your machine, not because it has to, but because you told it to.
I do not recommend this approach because it is slow and it is inefficient.
The purpose of this document is to show the reader that you will only get fast, precise info out of find if you give it decent search parameters.
How would you like it if I told you to rummage through your place and bring me back everything that is orange?
That might take you a spell, eh?
You'd probably want me to be a bit more specific and maybe narrow down the scope to just one room or two.
Same thing with find. I am looking for orange solid organic objects under 5 kg in your bedroom.
Ah, you get me your cat! Very good!
So, to illustrate, why not start with "the shotgun approach?" We can better this search gradually. You have probably all seen or used it at some point:
"find all files on this computer with "ssh" somewhere in the name"
$ find / -name '*ssh*'
/var/openssh
/home/mongoose/.ssh
/usr/sbin/sshd
/usr/share/man/info/en_US/aixcmds4/nisshowcache.jpg
/usr/share/man/info/en_US/aixcmds4/nisshowcache.htm
/usr/local/bin/sshold
...(pages & pages & pages)
Although this approach will certainly return a bunch of secure shell filenames to STDOUT, it is not very efficient, because the user is most likely looking for a more specific file.
Let's see if we can narrow out search down:
Maybe we suspect that our file is in either /var or /usr or /etc. Let it be known that you can list multiple paths; rarely should you be forced to search everything (You know the file isn't in /dev right? Then why have "find" search there?). Great! Lets modify the original:
$ find /var /etc /usr -name '*ssh*'
/var/openssh
/etc/security/ssh_banner
/etc/sshd_config
/usr/sbin/sshd
/usr/share/man/info/en_US/aixcmds4/nisshowcache.jpg
/usr/share/man/info/en_US/aixcmds4/nisshowcache.htm
/usr/local/bin/ssh
...(less pages!)
At least we are no longer having find search for our file in /dev or some other place where we know it is not.
How else can we differentiate our file? Oh yes, we are searching for a regular file, as opposed to a directory, a symlink, a block device (ex: a hard drive), a character device (ex: a tty), FIFO (a named pipe), or a socket. Unless we narrow it down, find will look at all file types when searching. Time to modify find with the -type flag, in this case, type "f" for a regular file:
$ find /var /etc /usr -type f -name '*ssh*'
/etc/security/ssh_banner
/usr/share/man/info/en_US/aixcmds4/nisshowcache.jpg
/usr/share/man/info/en_US/aixcmds4/nisshowcache.htm
/usr/local/bin/ssh
/usr/local/bin/ssh-add
/usr/local/bin/ssh-agent
...(one page!)
One more thing: maybe we also know that our file is owned by root and has permissions of 644 (rw-r--r--). We can define our search even further:
$ find /var /etc /usr -type f -user root -perm 644 -name '*ssh*'
/usr/local/etc/ssh_config
/usr/local/etc/sshd_config
/usr/local/etc/ssh_prng_cmds
/usr/local/etc/ssh_host_key.pub
/usr/local/etc/ssh_config.old
/usr/local/etc/sshd_config.old
/usr/local/etc/ssh_host_dsa_key.pub
/usr/local/etc/ssh_host_rsa_key.pub
Much better.
Does that make you want to learn how to extract the full power from this tool? I hope so because I can't count how many shell scripts I write in bash, ksh and sh whose functionality hinges on the find command to deliver the correct file(s), dir(s) or whatever for mangling ..err processing.
Useful Examples/Tips:
1) Here's one that will find and list all regular files set SUID to root (or anyone else with UID 0 ;)
# find / -type f -user 0 -perm -4000
2) This one finds all regular files that are world-writable and removes world-writability:
# find / -type f -perm -2 -exec chmod o-w {} \;
3) Find all files owned by no one in particular and give them to root:
# find / -nouser -exec chown root {} \;
4) Find all files without group ownership and give them to the system group:
# find / -nogroup -exec chgrp system {} \;
5) Find and gzip regular files in current directory that do not end in .gz
$ gzip `find . -type f \! -name '*.gz' -print`
6) Find all empty files in my home directory and delete after being prompted:
$ find $HOME -size 0 -ok rm -f {} \;
7) Find all files or symlinks in /usr not named fred:
$ find /usr \( -type f -o -type l \) \! -name fred
8) If you have a file with spaces, control characters, leading hyphens or other nastiness and you want to delete it, here's how find can help. Forget the filename, use the inumber instead. Say we have a file named "-rf .", spaces and all. We wouldn't dare attempt removing it the normal way for fear of issuing 'rm -rf /' at the command line.
$ echo jhjhg > "-rf /"
$ ls -la
total 4
-rw-r----- 1 mongoose staff 6 Nov 07 15:57 -rf /
drwxr-x--- 2 mongoose staff 512 Nov 07 15:57 .
drwxr-xr-x 3 mongoose bin 1024 Nov 07 15:53 ..
Find the I-number of the file using the -i flag in ls:
$ ls -lai .
total 4
18731 -rw-r----- 1 mongoose staff 6 Nov 07 15:57 -rf .
18730 drwxr-x--- 2 mongoose staff 512 Nov 07 15:57 .
1135 drwxr-xr-x 3 mongoose bin 1024 Nov 07 15:53 ..
^^^^^
There it is: I-node 18731. Now plug it into find and make find delete it:
$ find . -inum 18731 -ok rm {} \;
rm ./-rf . (?) y
$ ls -la
total 3
drwxr-x--- 2 mongoose staff 512 Nov 07 16:03 .
drwxr-xr-x 3 mongoose bin 1024 Nov 07 15:53 ..
Ta daaaa! all gone.
Usage:
find pathname(s) condition(s)
At least one pathname must be specified, but many can be entered as well. conditions can be grouped within escaped parenthesis (see Example #7), negated by preceding with an escaped exclamation point (\!, see Example #7) or given as logical alternatives to one another by separating them with "-o" (logical OR, -o, see Example #7)
Conditions: (I list common ones, but know that there are even more! man find)
-atime +n|-n|n find files last accessed (+n) more than n days ago, (-n) less than n days ago or (n) exactly n days ago. (Note: find will modify this value since it will access the file when searching for it.)
-ctime +n|-n|n find files last changed (+n) more than n days ago, (-n) less than n days ago or (n) exactly n days ago. (Note: Change refers to any modification, ownership or perm modification.)
-mtime +n|-n|n find files modified (+n) more than n days ago, (-n) less than n days ago or (n) exactly n days ago.
-exec cmd {} \; Execute script or command cmd on all files matched. The braces represent the matched file; don't forget to terminate this condition with the escaped semicolon shown. See Examples #2-#4. Tip: use ls as the command to -exec to test your returns before -exec'ing a more destructive command like rm
-ok cmd {} \; Again, execute script or command cmd on all files matched. This condition will prompt the user before executing cmd, though. Safer than -exec. See Examples #6 & #8
-group grp Return files belonging to grp. grp can be group name or GID.
-nogroup grp Return files NOT belonging to grp. grp can be group name or GID.
-user usr Return files belonging to usr. usr can be username or UID.
-nouser usr Return files NOT belonging to usr. usr can be group name or GID.
-inum num Find the file with inode number num.
-name pattern Find files matching pattern. Metacharacters must be quoted or escaped.
-newer filename Find files newer than filename.
-perm nnn Find files with octal permission pattern nnn. Precede nnn with a minus sign to match all files with at least the perm specified. Example: -1 matches all files with executable bit set for the world, or ********x. See Examples #1 & #2.
-type type Return all files of type type. type can be l (link), f (regular file), d (directory), s (socket), p (fifo), b (block special), or c (character special). See Examples #1, #2, #5, & #7.
-maxdepth num [GNU find only!] Find all files within a maximum directory depth of num. Keeps find from descending too deeply into the depths of some dir when you know the target(s) is(are) close.
-print Print matching filenames to STDOUT. This is deprecated, find should print no matter what, but being explicit can't hurt.
Presented by Chuck Geigner (mongoose) to UHACC. Copyright © 2001. Doc updated Jul 2006. Licenced granted for use under the LGPL.
|
Upcoming Events
UHACC Pre-Meeting
Wednesday Evenings, ~5:15-6:30pm - Lunker's
Officially unofficial pre-meeting meeting.
Come. Eat. Geek.
UHACC Meeting
Every Wednesday - 7:00-9:00pm
IWU Center for Natural Science Learning and Research, Fishbowl, floor 2.
[Directions]
Join us every Wednesday for our usual gratuitous display of geekiness. Meetings are free and attendance is open.
Hope to see you there!
|