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:
- Have a practice directory linked and mounted to other practice directories.
- Use xargs rather than the non-intuitive exec command.
- Use -exec echo {} for sanity and safety
- Semi colon is special and you are escaping it therefore the escape char is first
- 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 usexargs
:(or the files-with-spaces-and-other-nonsense-in-them-safe version)
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 tobash
. 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:
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:
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:Note that the + typically doesn't need to be escaped, but it's good to get in to the habit of doing so anyway.
This is what man is for: It can be hard to remember things, that is why *nix command includes man pages. You can just always check the ACTION section of the man page for a reminder on the syntax:
man find
. Although man pages may seem not to friendly, once you get good at reading them they are very handy.Make a Front-End or Wrapper: When I wanted to get better at GNU find I wrote a GUI front end for find that generates find commands with python, glade, and pygtk. This is a good exercise if want to get to know it really well.
Have a Practice Directory: Lastly, I always have a 'scrap' directory in my home dir for playing with powerful commands when something like 'echo' doesn't cut it. You can use shell expansion to quickly make a bunch of files with something like:
You can also combine find expressions with '-and' and '-or' operators. -and is implicit:
is the same as
The or operator can reduce your list of 4 commands to 2:
And finally, not related to find, but chown can also set the group as well. So, coping with spaces in names as well we end up with:
When closing I just think of using ; like with many programing languages and then escaping it. Just remember that is needs to be escaped and it comes to you pretty easily.
Depending on the version of find that you are using there are different options that may help you. GNU find is probably the most powerful and this may help you with your second (implied) question
For instance -- the default behaviour is not to dereference symbolic links, but you can override that; and the -mount option stops find going across mount points
Look in your local man pages
For some shells (not bash) escape {} for proper behavior.
find manual is good for mastering find.
Some would argue that the xargs option is faster than the -exec option because it won't execute the command once for each file, but I wouldn't worry about that for anything except massive jobs taking a non trivial amount of time.
Personally, I usually just run find without exec
make sure that the output looks correct, and then run my command on that list.
Before you do anything like this make sure the directory your running this command against isn't in the same filesystem as /usr or /etc. (otherwise if I have a hard link to /etc/passwd or to /bin/sh in my home directory you've just given me ownership of those and as a side-effect I now own the machine).
If you want to recurse through a directory and chown all the files/directories, a simple
chown -Rh user:usergroup user/
will do it. Make sure you use the -h or chown will follow symbolic links.