How do I master the UNIX find command?

I think I am fairly advanced in my use of find but EVERY time I use it I cannot for the life of me remember the method to close the -exec option. I spend a good deal of time reading every time I use it. Am I simply not using it enough or expecting too much of myself? Lets start with a typical example that gets me frustrated.

Directory structure has files with all incorrect permissions hidden files symbolic links etc. I want to change the ownership to a reasonable value

find . -type f -exec chown username {} \;
find . -type d -exec chown username {} \;
find . -type d -exec chgrp usergroup {} \;
find . -type f -exec chgrp usergroup {} \;

(Forgive me if the ending is backwards... I looked at it an hour ago and still I am not sure)

But I am scared to run it because of mounts, symbolic links, etc. I have made the ultimate goof of chmod .* and had it recurse upwards on me before. I know -xdev will forgo crossing partitions but I am not sure what will happen to the files living inside directories which are symbolic links.

So how does one master this beast that can kill crucial files?

Update pruning the best suggestions below and summarizing:

  1. Have a practice directory linked and mounted to other practice directories.
  2. Use xargs rather than the non-intuitive exec command.
  3. Use -exec echo {} for sanity and safety
  4. Semi colon is special and you are escaping it therefore the escape char is first
  5. The -or command can help you combine selection criteria.

I am a little confused about the print0 but xargs has always been a bit on the not easy to understand at first glance practice that I try and avoid.


Well, as far as the -exec syntax goes, you could do like a lot of people, give up and use xargs:

find . -type f | xargs chown username

(or the files-with-spaces-and-other-nonsense-in-them-safe version)

find . -type f -print0 | xargs -0 chown username

Or, to try to remember the right thing to do with the semicolon, what you need to drill into your head is that you're using a semicolon to terminate the command that -exec is running, and you have to escape the semicolon because it has special meaning to bash. Which is why it's backslash semicolon. You seem to have the {} substitution part okay.

As to killing files and so on, if you're running something big and dangerous like you're talking about, first do this:

find . -type f -exec echo chown username {} \;

and review the results. This is basically a "dry run" where you're seeing the commands it would run if you let it. Definitely a good practice. Won't help with the .* problem, but you know not to do that one now. :)


I'm surprised nobody has yet mentioned the following option:

find . -type f -ok chown username {} \;

This syntax will confirm the command before executing it. It works best if you expect your match to be a relatively small number of files because it will prompt for each one.

Some answers mention xargs, but with GNU find that too is unnecessary:

find . -type f -exec chown username {} \+

Note that the + typically doesn't need to be escaped, but it's good to get in to the habit of doing so anyway.