Sunday, September 13, 2009

Practical Unix/Linux GNU Find Command Examples

Find is a very popular program for searching for a particular set of files. If you combine the find command with other applications like 'grep' or any other command then you will be even more productive. Here are some practical examples in the listings below. The commands are run Mac OSX, Darwin Kernel Version 9.8.0.

Find Man Page (bsd unix)

find -- walk a file hierarchy

find [-H | -L | -P] [-EXdsx] [-f pathname] pathname ... expression
find [-H | -L | -P] [-EXdsx] -f pathname [pathname ...] expression

The find utility recursively descends the directory tree for each pathname
listed, evaluating an expression (composed of the ``primaries'' and
``operands'' listed below) in terms of each file in the tree.

Basic Find

Here the most basic usage for find.

After running the command, a listing of the files with the extension .m (objc code) are displayed.

Basic Find, other extensions

Here is an example of find with .m files and .h files.

227:octanemech berlinbrown$ find . \( -name '*.m' -or -name '*.h' \)

Find and executing commands on each file
The find command is not as powerful by itself. You can execute commands on each file that will be returned by the find command. Here is a useful example, find a set of files and perform grep on each file.

27:octanemech berlinbrown$ find . -name '*.m' -exec grep -H Berlin {} \;
./Classes/EAGLView.m:// Created by Berlin Brown on 9/2/09.
./Classes/octanemechAppDelegate.m:// Created by Berlin Brown on 9/2/09.
./main.m:// Created by Berlin Brown on 9/2/09.
227:octanemech berlinbrown$

The {} argument expands to a set of filenames.

Here is another common one-liner, remove all of the subversion .svn system directories. This command will turn your directory back to the way it was before you used it for your subversion project.

find . -name '.svn' -exec rm -Rvf {} \;

Find, exec and wc (line/character count)
I am software developer and I am need to use the wc command to count the number of lines in a source file. Here is an example:

227:octanemech berlinbrown$ find . -name '*.m' -exec wc -l {} \;
276 ./Classes/EAGLView.m
542 ./Classes/octanemechAppDelegate.m
323 ./Classes/Texture2D.m
18 ./main.m


227:octanemech berlinbrown$ wc `find . -name '*.m'`
276 826 8426 ./Classes/EAGLView.m
542 1830 17171 ./Classes/octanemechAppDelegate.m
323 1216 10513 ./Classes/Texture2D.m
18 48 364 ./main.m
1159 3920 36474 total
227:octanemech berlinbrown$ wc -l `find . -name '*.m'`
276 ./Classes/EAGLView.m
542 ./Classes/octanemechAppDelegate.m
323 ./Classes/Texture2D.m
18 ./main.m
1159 total

There is one issue with running find this way, you may not get the totals, I want to use awk in one of the find/wc examples:

227:octanemech berlinbrown$ find . \( -name '*.h' -or -name '*.m' \) -exec wc -l {} \; | awk '{s+=$1} END {print s}'

In natural language, after running the command above, it might read as; Find all of the files with the extension .h or .m, execute the wc command on the files, pipe the output to awk and sum the total.
Adding more filters
Here is the one-liner to find files that or at least 5k.

find . -name '*.m' -size +10k

27:octanemech berlinbrown$ find . -name '*.m' -size +1k

To find the files that have been modified within the last day:

find . -mtime -1
or 60 minutes...
find . -mmin -60

More Find Examples

Find then do a search and replace with 'sed' (replace with empty string):

find -name '*.java' -exec sed -i 's/SOME_KEYWORD//g' {} \;

Find files with *.h,*.m extensions and copy to a directory:

find -name '*.h' -or -name '*.m' -exec cp -vf {} ./tmp \;

Count number of total lines for a set of files using awk:

find . -name '*.d' -exec awk '{print NR}' {} +

$ wc -l `find . -name '*.m'` | sort
370 ./Inputs/Gesture.m
378 ./Models/k_wing.m
422 ./TouchFighterAppDelegate.m
444 ./GameObjects/Bullets.m
473 ./Core/ParticleSystemObject.m
572 ./Support/OpenGL/Texture2D.m
837 ./GameObjects/SpaceShip.m
1343 ./TouchFighterView.m
12745 total

1 comment:

seenxu said...

the \( \) thing of find is really helpful, thx.