[lug] "find" question

Daniel Webb lists at danielwebb.us
Tue Aug 17 23:32:40 MDT 2004


Aha!  I'm embarassed, but I didn't even know about the -xtype option.
Here's the command I wanted all along:

find . -follow \( -type f -a \! -xtype l \)

-xtype solves the problem I was having when only using -type.  GNU
tools are the best!

Rephrased, what I want to accomplish is:

List all non-link files in a directory tree.  Directory symbolic links
should be followed.  The way I have been using this in a script is:

FILES=$(find . -follow \( -type f -a \! -xtype l \) | tr '\n' ':')
IFS=":"
for FILE in $FILES; do
   something
done

I thought the best would be to use

IFS=$(echo -e "\n")

and not use the tr '\n' ':' bit, but that didn't seem to work.  Word
splitting didn't work and I got $FILE == $FILES.

Daniel

On Tue, 17 Aug 2004, Tkil wrote:

> >>>>> "Daniel" == Daniel Webb <lists at danielwebb.us> writes:
>
> Daniel> I want to search a directory tree, dereferencing symbolic
> Daniel> directory links, but not dereferencing symbolic file links.
> Daniel> What is the easiest way to accomplish this?
>
> I'm not sure what you're trying to do here, and the later conversation
> hasn't enlightened me.
>
> What do you mean by "dereference" here?
>
> >From the point of "find", I take "dereference" to mean either
> examining the target file (as opposed to the link itself), or it can
> mean traversing into a directory.
>
> If you mean the latter, then I don't see the problem -- if it's a
> symlink to a file, there's nothing to descend into, so there's no
> problem.  If it's a symlink to a directory, "-follow" is what you
> want.
>
> So I assume you mean the former, in which case GNU find has "-xtype".
>
> If you mean something else, please give us an example of what you're
> actually trying to accomplish.
>
> With regards to spaces and newlines in filenames -- 'find' has
> "-print0", which works well with 'xargs' "-0".  Perl also has a "-0"
> flag (see "man perlrun") if you want to do manipulation on the
> filenames.
>
> If your predicates get any more complicated, however, and if you do
> have to be paranoid about well-formed file names, then I would
> probably abandon the idea of doing this in shell, and resort to a
> scripting language.  In my case, I'd use Perl (probably with
> File::Find, but the setting the symlink flags properly is almost as
> difficult as writing a basic traverser).  I'm sure that Python has
> equivalent libraries.
>
> But I still don't know what what you're looking for.  You can control
> whether or not symlinked directories are traversed with "-follow" (and
> maybe also "-prune"); you can control what type of files are printed
> with "-type" and "-xtype".
>
> Making a quick hierarchy with these commands:
>
> | $ mkdir a b
> | $ ln -s b c
> | $ touch a/foo b/bar c/baz
> | $ ( cd a ; ln -s ../b/bar ./lbar )
>
> Looks like this:
>
> | $ ls -lR
> | .:
> | total 0
> | drwxr-xr-x  2 tkil users 16 Aug 17 15:23 a
> | drwxr-xr-x  2 tkil users 16 Aug 17 15:23 b
> | lrwxrwxrwx  1 tkil users  1 Aug 17 15:23 c -> b
> |
> | ./a:
> | total 0
> | -rw-r--r--  1 tkil users 0 Aug 17 15:23 foo
> | lrwxrwxrwx  1 tkil users 8 Aug 17 15:24 lbar -> ../b/bar
> |
> | ./b:
> | total 0
> | -rw-r--r--  1 tkil users 0 Aug 17 15:23 bar
> | -rw-r--r--  1 tkil users 0 Aug 17 15:23 baz
>
> You can use 'find' like so:
>
> | $ find . -type l
> | ./a/lbar
> | ./c
> | $ find . -xtype l
> | $ find . -follow -type l
> | $ find . -follow -xtype l
> | ./a/lbar
> | ./c
>
> If you want the names of directories (only) that are symbolic links:
>
> | $ find . -follow -xtype l -type d
> | ./c
>
> And if you want to see what they point to:
>
> | $ find . -follow -xtype l -type d -print0 | xargs -0 ls -al
> | lrwxrwxrwx  1 tkil users 1 Aug 17 15:23 ./c -> b
>
> But as I've said before (sorry for repeating myself!) I'm not sure
> this is what you're looking for.
>
> As for actually parsing out the name and target of a link, you're in
> trouble: remember that the sequence " -> " is perfectly valid (if a
> very bad idea) in unix file names, and you can't rely on the column
> offset being the same either.  Ah-ha, there's "readlink" command:
>
> | $ find . -follow -xtype l -type d -exec readlink '{}' \;
> | b
>
> If you need both, and are still paranoid about weird file names, I'd
> again likely rely on a scripting language where I'm more comfortable
> with the quoting situation:
>
> | $ find . -follow -xtype l -type d -print0 | \
> | >   perl -0 -lnwe 'my $d = readlink $_; print "$_ => $d\n";'
> | ./c => b
>
> Good luck,
> t.
>




More information about the LUG mailing list