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?

3 Answers
3

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):

I'd recommend two changes to this script. One, use find rather than globstar; two, instead of looking at the head, use the file command to see what it is and branch from there.
–
ShadurNov 12 '11 at 15:52

@Shadur find is less reliable than globstar, globstar is preferable in almost every case.
–
Chris DownNov 15 '11 at 21:58

@ChrisDown Whoa! find and globstar each have their good and bad points in terms of reliability, portability, clarity, efficiency, …
–
GillesNov 15 '11 at 22:10

Make that grep -L '^#!' at least (the quotes are necessary, and ^ restricts to matching at the beginning of the line), but it's still too permissive as it matches #! on any line. Using xargs will fail with file names containing spaces or quoting characters; use xargs -d '\n' (requires GNU xargs).
–
GillesAug 27 '10 at 21:30

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.