[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