Chmod: How to Recursively Add Execute Permissions Only to Files Which Already Have Execute Permission

Chmod recursively

You need read access, in addition to execute access, to list a directory. If you only have execute access, then you can find out the names of entries in the directory, but no other information (not even types, so you don't know which of the entries are subdirectories). This works for me:

find . -type d -exec chmod +rx {} \;

chmod: How to recursively add execute permissions only to files which already have execute permission

Use find:

find . -perm /u+x -execdir chmod a+x {} \;

How do I change permissions for a folder and its subfolders/files?

The other answers are correct, in that chmod -R 755 will set these permissions to all files and subfolders in the tree. But why on earth would you want to? It might make sense for the directories, but why set the execute bit on all the files?

I suspect what you really want to do is set the directories to 755 and either leave the files alone or set them to 644. For this, you can use the find command. For example:

To change all the directories to 755 (drwxr-xr-x):

find /opt/lampp/htdocs -type d -exec chmod 755 {} \;

To change all the files to 644 (-rw-r--r--):

find /opt/lampp/htdocs -type f -exec chmod 644 {} \;

Some splainin': (thanks @tobbez)

  • chmod 755 {} specifies the command that will be executed by find for each directory
  • chmod 644 {} specifies the command that will be executed by find for each file
  • {} is replaced by the path
  • ; the semicolon tells find that this is the end of the command it's supposed to execute
  • \; the semicolon is escaped, otherwise it would be interpreted by the shell instead of find

(How) is it possible to add the x permission only to those who already have the r permission using standard shell commands and/or Unix utils?

The answers provided so far present useful ideas, but, as none of them answers the question as asked, I am hereby posting an answer to my own question.

This answer presents three different solutions, each based on a different approach suggested in the previously posted answers; there are other ways too which are not covered (I'll only mention, without showing the actual code, the trick of getting the permissions as an octal number, and then – using some mechanism of performing arithmetic/bit-wise calculations – anding it with 444 to get the r bits, shifting right 2 bits to get the corresponding x bits, oring with the original permissions, and setting the result as the new permissions).

All of the solutions below assume working on the file "$FILE".

Solution 1 – ifing on the pattern of the current permissions as text

This is perhaps the most straightforward approach:

permissions=$(stat -f %SA "$FILE")
if [[ $permissions =~ .r........ ]]; then chmod u+x "$FILE"; fi
if [[ $permissions =~ ....r..... ]]; then chmod g+x "$FILE"; fi
if [[ $permissions =~ .......r.. ]]; then chmod o+x "$FILE"; fi

Solution 2 – using find, taking advantage of the -perm and -exec options

This approach uses find not to find multiple files, but rather to either find the given file (in case it has a certain permission) or to not find anything (otherwise), and to set the matching desired permission in case the file is found (and do nothing otherwise):

find "$FILE" -perm -u=r -exec chmod u+x {} \;
find "$FILE" -perm -g=r -exec chmod g+x {} \;
find "$FILE" -perm -o=r -exec chmod o+x {} \;

The three cases can easily be combined into a single for loop:

for w in u g o; find "$FILE" -perm -$w=r -exec chmod $w+x {} \;; done

Solution 3 (zsh only) – using glob qualifiers

This approach runs each of the relevant chmod commands on "$FILE" only in case it already matches the corresponding permission. Note || : is added to avoid errors in case there's no match, i.e. if the file does not have the corresponding permission (also note zsh still emits a no matches found warning in this case):

chmod u+x "$FILE"(r) || :
chmod g+x "$FILE"(A) || :
chmod o+x "$FILE"(R) || :

How to set permissions recursively, 700 for folders and 600 for files, without using find

Apparently this is very easy to implement. There are 2 ways: using chmod only, or setting ACL (access control list) on the desired path:

  • Using chmod i would run:
    chmod -R 600 /path          # to remove executable permissions
    chmod -R u=rwX,g=,o= /path # to make directories transversable

for the user owner i'm giving capital "X", so it does apply only to directories and not files.

  • Using ACL:

    setfacl -Rm u::rwX,g::0,o::0 /path
    setfacl -Rm d:u::rwX,g::0,o::0 /path

again using capital X so it applies only to directories and not files. The first command applies the ACL, the second one makes it default policy so newly created files will inherit the desired permissions.

Linux: Set permission only to directories

Use find's -type option to limit actions to files and directories. Use the -o option to specify alternate actions for different types, so you only have to run find once, rather than separately for each type.

find htdocs -type f -exec chmod 664 {} + -o -type d -exec chmod 775 {} +

Is there a shell command to recursively give permission to directories and files?

First line changes file permissions, and the second changes directory permissions in the active directory and its subdirectories.

find . -type f -print0 | xargs -0 chmod 644
find . -type d -print0 | xargs -0 chmod 755

Chmod 777 to a folder and all contents

If you are going for a console command it would be:

chmod -R 777 /www/store. The -R (or --recursive) options make it recursive.

Or if you want to make all the files in the current directory have all permissions type:

chmod -R 777 ./

If you need more info about chmod command see: File permission

Chmod: Execute only if the file is a directory

find my/path -type d -exec chmod u=rwX,g=rwX,o=r {} \;
+ + + + +------+------+ + +
| | | | | | +-> semicolon needed by -exec and escaped to avoid shell expansion
| | | | | +-----> current directory entry returned by find
| | | | +--------------> your chmod options
| | | +-------------------------> the shell command you want to execute on each directory entry
| | +-------------------------------> need to execute a command for each entry returned by find
| +-----------------------------------> look for directories only (not files/symlinks/etc)
+----------------------------------------------> the path to look for entries in


Related Topics



Leave a reply



Submit