I accidentally chmod -R +x on a directory. How do I restore the correct permissions?

Well, to be specific, it was chmod -R 755. Now every file is executable, which I don’t want.
I am thinking that I should look at the first two bytes of each file for the #!, but will this cover everything? Should I instead use file to look at everything and base my decision on that? Or, more likely, is there an even better way to do this?

What is the preferred way to recursively go through a directory and set -x on files that are not ‘supposed to be’ executable?

Asked By: Larry Wang


Well, without a shebang line, the file will be executed as a shell script, nominally with /bin/sh. You’re idea is a good start and on the assumption that the directory in question doesn’t contain mission-critical files there probably isn’t much risk to executing some grep and chmod combo. You may encounter false positives, i.e., files with a shebang line that are not meant to have their executable bit set but without knowing more information on the purpose of what’s in the directory, only you can decide whether that poses a significant existential threat to your system and/or data.

Answered By: gvkv

I believe you will want something like

find dir -type f -exec chmod ugo-x '{}' +

This looks for all regular files, recursively in dir, (it excludes directories, and devices) and removes the executable bit.

I would start here, and then work my way towards making files that are supposed to be executable, executable.

The following should work exactly as you asked for ( it will find all regular files, grep them for #! and then remove the x bits if not found )

find . -type f | xargs grep -L #! | xargs chmod ugo-x

possibly a better version of the above (less pipes)

find . -type f -exec grep -L #! '{}' + | xargs chmod ugo-x 
Answered By: xenoterracide

There’s no magic bullet here. The permissions carry information which is not always redundant.

If you’d done this in a system directory, your system would be in a very bad state, because you’d have to worry about setuid and setgid bits, and about files that are not supposed to be world-readable, and about files that are supposed to be group- or world-writable.

In a per-user directory, you have to worry about files that aren’t supposed to be world-readable. No one can help you there.

As for executability, a good rule of thumb would be to make everything that doesn’t look like it could be executed, be nonexecutable. The kernel can execute scripts whose first two bytes are #!, ELF binaries whose first four bytes are x7fELF where x7f is the byte with the value 12, and a few rarer file types (a.out, anything registered with binfmt_misc). Hence the following command should restore your permissions to a reasonable state (assumes bash 4 or zsh, otherwise use find to traverse the directory tree; warning, typed directly into the browser):

for x in **/*; do
  if ! [ -f "$x" ]; then continue; fi # skip all but regular files
  case $(head -c 4 "$x") in
    "#!"??) :;; # skip script
    "x7fELF") :;; # skip ELF executable
    *) chmod a-x "$x";;

Note that there is a simple way to back up and restore permissions of a directory tree, on Linux and possibly other unices with ACL support:

getfacl -R >saved-permissions
setfacl --restore=saved-permissions
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.