recursively change file permission but not directories?

9,045

Solution 1

The better solution should be

chmod -R ug=rwX,o=rX /path

where the capital X means: set execute bit if

the file is a directory or already has execute permission for some user

(quoted from chmod man page).

Or also, if you want to use find

find /path \( -type f -exec chmod ug=rw,o=r   {} + \) -o \
           \( -type d -exec chmod ug=rwx,o=rx {} + \)

Solution 2

Using find is the 'right' way, and the only programmatic way, although there are variations:

find . -type f -exec chmod ug+rw {} +  # "+" may not be on all systems

or

find . -type f -print0 | xargs -r0 chmod ug+rw  # similar to the -exec + functionality

or the slowest:

find . -type f -exec chmod ug+rw {} \;  # in case xargs is not installed

Each of these selects a file (not directory, not symlink) and applies the chmod command on it. The first two reduce the number of calls to chmod by appending the file to the end of an internal command line each time until a maximum is reached (often 10), then calls the command and starts rebuilding a new command. The last statement spawns a new process for each file, so it is less efficient.

Share:
9,045

Related videos on Youtube

user394
Author by

user394

Updated on September 18, 2022

Comments

  • user394
    user394 over 1 year

    I was doing a mass recursive change of permissions of some files that I had migrated to a unix system. I changed them to ug+rw, but then I found that I could not traverse subdirectories. I looked at the man page for chmod and didn't see any explanation for excluding directories, so I googled a little and found that people used find to recursively change the permissions on directories to 'execute' for user and group. I did that and then I could look into them.

    But it seemed to me that I should be able to be able to do this find chmod -- to recursively change the files to read/write but not make the directories untraversable. Have I done this the 'right' way or is there a simpler way to do it?

  • The Dude
    The Dude over 9 years
    I used the wide open for everyone version of this command for my USB hard drive: chmod -v -R ugo=rwX /path Thanks!
  • Wildcard
    Wildcard over 8 years
    Evidently there is no way without using find to set all file permissions to 600 and all directory permissions to 700. (I arrived here through my googlings on the subject.) If that can be done with a single chmod -R command, feel free to correct me.
  • enzotib
    enzotib over 8 years
    @Wildcard: not exactly, the command chmod -R u=rwX,go= /path does almost what you want: it sets all dirs to 700 and all files to 600 or 700, depending on if the execution bit is already set or not, and I think this is the right thing to do.
  • Wildcard
    Wildcard over 8 years
    @enzotib, yes—almost, but not quite. In my case I want to disable the execution bit for all files (but not directories of course) regardless of whether they are scripts or binaries or whatever. So the find command you wrote was very helpful as a template. :)
  • Michael
    Michael about 8 years
    @Wildcard what about removing the execute bit first, recursively, then add it back only to directories using the above command?
  • Wildcard
    Wildcard about 8 years
    @Michael, that would be fairly error-prone as once the execute bit is removed on a directory, you can't access any of the files inside. So you'd have to ensure you were doing a strictly depth-first search and only removing the execute bit at the deepest level. Not sure how to do that with find; the answer given here is simpler.
  • Admin
    Admin almost 2 years
    POSIX requires find to support -exec ... {} +; see pubs.opengroup.org/onlinepubs/009695399/utilities/find.html . On the other hand, it doesn't require find to support -print0, nor xargs to support -0.