Possible Duplicate:
How to chmod 755 all directories but no file (recursively) ?

I've just upgraded from Ubuntu 8.04 to 9.04, added an extra hdd for /home and used an iPod (FAT32, sadly) to hold/transfer the files in the interim.

Copying these files back I've discovered that the majority of files, I think due to the issues of permissions being unset/improperly set on FAT32, have now effectively been chmod +x'ed at some point.

I was wondering if there's an easy way to find all files of a certain type (say .txt or .css) and pipe that directly to chmod -x? I've tried searching with various phrases on this site, and several others, but couldn't find anything. Though this may be a vocabulary issue, I guess.

Thanks for any help you guys are able to provide, and for your time.

marked as duplicate by quack quixote, Troggy Feb 14 '10 at 5:45

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

chmod -R a-x *.txt

would be an example of this, but you'd have to repeat it for all different file patterns.

  • Would that search for all .txt files on the machine, or would I have to nominate particular directories? And, because I may be an idiot, what do the switches/arguments do? Also, +1 for the answer =) – David Thomas Sep 12 '09 at 20:51
  • -R is a recursive change, there is also a long option: --recursive. I think it only does the current directory. a-x sets -x for all (user, group and others). – SilentGhost Sep 12 '09 at 20:59
  • if you have a set directory you want to execute this in, execute a cd /mydirectory, then execute the chmod command – Roy Rico Sep 12 '09 at 21:19
  • 1
    That wouldn't work. The --recursive option only has an effect if .txt includes any directories, in which case *all of the files in those directories will be chmodded. – Ryan Thompson Sep 13 '09 at 3:37

The command line can also use regexp type syntax, so you'd only have to execute your command one time.

cd /to/my/directory
chmod -R a-x *.(txt|css|whatever)

ok, i'm tried to test it, but it's not exactly working out, I'm looking for the correct syntax, but i know it's possible. Thx.

In the mean time..

This definitely works (and is definitely overkill):

find /to/my/directory -type f | egrep "(txt|css)$" | xargs -t -i{} chmod a-x {}


The find command will list all files, links and directories, each on a separate line. The path name specifies the starting point. The -type f option specifies to find files only.

the egrep command will output every line that matches the regular expression. The "(txt|css)$" regular expression says to match every file that ends with ($) with txt or css.

the xargs command will take the output of a command and pipe it into the input of another command (which comes after it). for example:

$> echo a\nb\nc 

$> echo a\nb\n\c | xargs echo
a b c

so normally, you could do find -type f | xargs echo but the output can sometimes get really long if you have alot of files, so i find it better to break it up. soo. the -i option executes the command for each line of output, the value of each line is stored in a variable, i defined as {}. the -t command outputs each command that is generated to the std out so you can see what is happening.

  • I would add that you should use find -print0 | xargs --null in order to handle files with spaces in their names. – Ryan Thompson Sep 13 '09 at 3:39
  • you would have to find a different way to do it, the grep command doesn't work (or didn't seem to with me) with the -print0 option. – Roy Rico Sep 13 '09 at 5:04
  • Grep also has null options, -z and -Z for input and output, respectively. But you don't need grep here. Find already has the -regex and -iregex options. You just need something like find DIR -type f -iregex '\.(txt|css)$' | xargs --null COMMAND – Ryan Thompson Sep 13 '09 at 21:44
  • ah cool, i haven't used the -iregex option, so i'll have to try that. – Roy Rico Sep 13 '09 at 23:01
  • shell patterns are so-called glob patterns, not regex. And your command would break on filenames with spaces or quotes. It's quite hard to safely print out and then parse filename. Traversing directories is laden with gotchas. e.g. stackoverflow.com/questions/1841737/… If you can use find -print0 | grep -0 | xargs -0, you're usually ok, though. – Peter Cordes Dec 10 '09 at 3:15

As an answer to your actual question, the find | xargs solution is the right one.

However, to address your root problem, it is impossible to correctly restore all the file permissions without a reference. If you have the space, you could create a virtual machine, install all the same packages (to find out how, search for dpkg get set selections) as your real machine, and then "copy" the permissions using chmod's --reference option.

If you decide to go this route, I can edit my post with more detailed instructions.

  • It was /home that he transfered using fat32, so at least most of it doesn't care about perms. – Peter Cordes Dec 10 '09 at 3:16

Ah, finding out the hard way you should have used tar to back / restore. :(

find . -type f -name '*.txt' -exec chmod -x {} +

Or with any other selector you want, e.g. find -regextype posix-extended . -type f -iregex '.*\.(txt|css|html)' -exec chmod -x {} +

Actually, hardly anything in your home directory should be executable, so I'd start with just find -type f (without -name), and then make things executable as necessary. Maybe chmod to mode 664, if you ended up with everything mode 777, since you don't want world write permission on your files (or directories either). So actually, chmod o-w -R ~ is a good idea.

Some files should not be readable by other users on the same machine, e.g. ~/.bash_history, ~/.ssh, ~/Mail, and so (based on what I have in my home directory that might actually matter)

    chmod 600 .bash_history .esd_auth .githistory  .ICEauthority .lesshst .mcoprc .netrc* .pulse-cookie .recently-used* .viminfo .Xauthority .xsession-errors
    chmod 700 .dbus .gconf* .gnome* .gnupg .icedteaplugin .kde .macromedia .metacity Mail .mozilla .openoffice.org* .pulse .purple .Skype .ssh .thumbnails .tsclient .update-notifier

    chmod 2700 .gnupg  # super-ultra-paranoid, I guess.
    chmod 500 .gvfs  # gvfs is weird, and maybe not present on current ubuntu?

copy/paste that into a terminal. Don't worry about errors, I'm sure you don't have all the same dotfiles and directories I do. (and I left out a lot of obscure ones that are really just game save directories, and could be publicly readable without harm.) Generally, if you don't want your pr0n stash or any mention of it to show up in other users' locate results, or other searches, make sure your history files and so on are private.

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