Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

My OS and home directory are on an SSD. I store some large files on a hard disk, and symlink from my home directory to the hard disk (eg. ~/Videos/Films is a symlink to /mnt/hdd/Films). I also have a number of Wine prefixes, each of which has dosdevices/z: symlinked to /.

So, if I used find without -L, it will miss everything that's on the hard disk. But if I use find with -L, it ends up in a loop due to Wine's symlink to /.

Is there any sensible way of resolving this, so that find searches where I want it to? Intuitively, I'm wanting something along the lines of "follow symlinks, unless they're under a directory called dosdevices". "Follow symlinks that are to something on the hard disk" would work too.

share|improve this question

2 Answers 2

up vote 1 down vote accepted

The -prune primary tells find not to recurse under a directory.

find -L -path ~/.wine/dosdevices -prune -o -type f -name 'My Favorite Movie.*' -print

If you want to use -lname in your condition, you can't use the -L option, because -L causes most predicates to act on the target of the link, including -lname. My recommendation in that case would be to use both your home directory and the hard disk root as the roots of your search.

find ~ /mnt/hdd -xtype f -name 'My Favorite Movie.*'

You might run find ~ -type l … to gather a list of symbolic links and use them as additional roots.

( IFS=$'\n'; set -f;
  find ~ $(find ~ -type l -lname '/mnt/hdd/*') \
       -xtype f -name 'My Favorite Movie.*' )

If you really want to recurse under symbolic links, you can exclude specific symbolic links by target instead of by name. However you can only exclude a finite list, not a pattern or subtree this way.

find -L \( -samefile /exclude/this -o -samefile ~/and/that \) -prune -o \
     -type f -name 'My Favorite Movie.*' -print

You can use other criteria such as ! -writable (files that you don't have write permission to), but I don't think GNU find has a way to recurse under symbolic links only if their target text matches a certain expression.

You could build a find command that does almost what you want except for not excluding enough symbolic links, run find2perl to convert the query to a Perl script, and tweak the Perl script a bit. There are many switches of GNU find that find2perl doesn't recognize, however.

share|improve this answer
    
Thanks! -prune is just the sort of thing I was looking for. I've found that find ~ \( -lname ~ -o -lname ~/\* -o -lname / \) -xtype d lists all the symlinks that I don't want to follow; I'm now trying to find a way to use that query to prune. –  Mark Raymond Jan 1 at 11:00
    
@MarkRaymond The general principle is find ~ <negative criteria> -prune -o <positive criteria> -print, so find ~ \( -lname ~ -o -lname ~/\* -o -lname / \) -xtype d -prune -o <whatever it is you want> -print –  Gilles Jan 1 at 15:09
    
@Giles - that works fine without -L, but once I add -L, the -lname expressions don't work any more (as the man page says they won't). So basically I then need some conditions to follow symlinks and others not to! –  Mark Raymond Jan 1 at 15:50
    
I can't think of a way of doing exactly what you want with find. See my edit for some approximations. –  Gilles Jan 1 at 16:21

How many symlinks to hard disks do you have? If it is not too many one solution is to not use "-L" while explicitly specifying the symlinks that you do want to follow on the find command line. Something like:

find .  ~/Videos/Films -name '*file I want*' ...

This will search the current directory (".") as well as the symlink "~/Videos/Films" but will not descend into other symlinks.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.