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
-execsyntax goes, you could do like a lot of people, give up and usexargs: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 usernameOr, 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
-execis 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:
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. :)Steve Folly : +! for the 'echo' practice dry run. I always use this for a big changeFrom chaos -
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.
From Garry Harthill -
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.
\{\} or '{}'find manual is good for mastering find.
wzzrd : No you don't; find runs just fine with the {} as they are. They are part of the find command: they are a token that gets replaced by the result of the find command. They only mean something in bash when defining functions or calling variables, so you can just use them as in the original question.Ian Kelling : Its from the man page. I updated to say its not applicable to bash.From Ian Kelling -
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
find /path/to/dir -name whatevermake sure that the output looks correct, and then run my command on that list.
chown user:group `find /path/to/dir -name whatever`Ian Kelling : Perfect example of how "not" to do things. Filenames with spaces.theotherreceive : Yep, that's a potential problem which I should perhaps have acknowledged. However my point was about reading the find output before executing anything, where you would spot spaces or other file name madness.From theotherreceive -
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.
ojblass : Can you explain the nature of the plus sign... what exactly is it doing? Is the shell processing it or the command. I think I am going to download the source code for gnu-find because this is an interesting topic.Kamil Kisiel : find is processing it. Read man find to find out more about that option.From Kamil Kisiel -
You can also combine find expressions with '-and' and '-or' operators. -and is implicit:
find . -type f -name "plainfile" ...is the same as
find . -type f -and -name "plainfile" ...The or operator can reduce your list of 4 commands to 2:
find . -type d -or -type f ...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:
find . -type d -or -type f -exec chown username:usergroup '{}' \;ojblass : What find with the -or business. [Sic]Steve Folly : @ojblass: find combines expressions using 'and' or 'or', by default if neither '-and' nor '-or' are specified, '-and' is used implicitly. So type 'find -type d -type f' will not find anything because nothing is a directory *and* a file.From Steve Folly -
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:
for i in {1..100}; do touch "$i"; doneojblass : Strange a practice directory is something I have never considered.From Kyle Brandt -
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.
ojblass : I don't think this is cross platform. Also fails with 247K of files as demonstrated by my practice environment. I am not sure why.chris : I think you've found a bug more than you've found a crossplatform issue. Which version and what's the exit status when it fails? As far as I can tell it first originated in early bsd versions; it's definitely in sunos 5.3 and ultrix and irix. How many does it process before it fails?ojblass : You are right it works on AIX 5.3, AIX 5.2, but not AIX 4.3, NCR, HP 11, HP 10.20, or my DSL distributions. IN all cases it appears to fail at or near 60k files.From chris
0 comments:
Post a Comment