9fans archive / 2002 / 10 / 655 prev next
From: Dan Cross <cross@mat...>
Subject: find(1) revisited.
Date: Thu, 31 Oct 2002 16:58:01 -0500
Oh! I forgot to say how to use these. Sorry, my bad. Basically,
compile walk and put it and sor in your bin directories. Walk takes
``-d n'' to limit the depth of the walk to the nth level in the target
directory (walk -d 0 prints nothing), and ``-q'' to quote the output in
the style of ls(1). These can of course be used in concert. For
example, `walk -d 3 -q /dev' prints out everything up to 3 levels deep
in /dev, quoting everything that needs to be. `walk -d 3 -q /dev /env'
might be a better demonstration, as I think it's a rare thing indeed
that something in /dev needs to be quoted.
Sor works sort of like grep, except that you pass it tests. For
instance, `walk -d 3 -q /dev /env | sor 'test -d' '' will print out
the names of all the directories up to depth 3 in /dev and /env.
Multiple tests can be put on the same line, effectively creating a
logical `or' operator. For example,
walk -d 3 -q /sys/lib | sor 'test -d' 'test -x'
(interestingly, this shows /sys/lib/ghostscript/font/mkfile is
executable on my system; how odd.)
Of course, the usual combinations with grep, sed, etc, will work.
A few Unix find idioms and their translations are:
unix% find $home -name '*foo*' -print
term% walk $home | grep foo
unix% find $home -name '*foo*' -type d -print
term% walk $home | grep foo | sor 'test -d'
unix% find $home '(' -name '*foo*' -o -name '*bar*' ')' -type d -print
term% walk $home | grep '(foo|bar)' | sor 'test -d'
unix% find $home/* $home/*/* -prune '(' -name '*foo*' -o -name '*bar*' ')' -type d -print
term% walk -d 2 $home | grep '(foo|bar)' | sor 'test -d'
unix% find $home -name foo.c -exec ls '{}' ';'
term% ls `{walk $home | grep '^foo.c$'}
Incidentally, sor internally sets the environment variable ``file'' to
the name of the current file being examined. This can be useful for
some tests. For example:
term% walk -d 1 | sor '/sys/lib/texmf/bin/386/newer $file'
Which is basically a goofy way of printing the names of files in
the current directory. Or the perhaps more useful:
term% walk -d 1 | sor 'grep README $file > /dev/null'
Which is a goofy way of doing: grep -l README `{walk -d 1}
Anyway, further examples exist, but already the combination of walk and
sor is just as expressive, but a lot shorter and simpler than find, et
al. Also, it's easy to write other programs that perform tests similar
to the rest of the find predicates (I have some simple scripts, for
instance, that pull the size and owner/group of a file out of ls -l's
output).
- Dan C.