Give execution permission to directories but not to files

8

3

I have a directory structure with files and directories and I like to assign permissions so all the files and directories have read-write permissions for the user and read permissions for the group and, additionally, execution permissions to the directory.

I would like to achieve something like that:

$ ls -l
total 16
-rw-r----- 1 daniel daniel    0  5月 23 16:20 1
-rw-r----- 1 daniel daniel    0  5月 23 16:20 2
-rw-r----- 1 daniel daniel    0  5月 23 16:20 3
-rw-r----- 1 daniel daniel    0  5月 23 16:20 4
-rw-r----- 1 daniel daniel    0  5月 23 16:20 5
drwxr-x--- 2 daniel daniel 4096  5月 23 16:00 a
drwxr-x--- 2 daniel daniel 4096  5月 23 16:00 b
drwxr-x--- 2 daniel daniel 4096  5月 23 15:59 c
drwxr-x--- 2 daniel daniel 4096  5月 23 15:59 d

Daniel

Posted 2014-05-23T07:37:14.463

Reputation: 238

Answers

12

To give execution (search) permission to directories, but not to files, use:

chmod -R +X .

To assign all the permissions as in your example, use:

chmod -R u=rwX,g=rX,o= .

-R changes files and directories recursively, while +X sets execute/search only if the file is a directory or already has execute permission for some user. r and w are of course for reading and writing, respectively.

Mode X (upper x) is documented in both the traditional manual page1 and the info documentation2.

It should also work on other Unix like systems, e.g. FreeBSD, NetBSD or OpenBSD. Quoting from the chmod(1) man page of The Open Group Base Specifications Issue 7, 2018 edition:

The X perm symbol was adopted from BSD-based systems because it provides commonly desired functionality when doing recursive (-R option) modifications. Similar functionality is not provided by the find utility. Historical BSD versions of chmod, however, only supported X with op+; it has been extended in this volume of POSIX.1-2017 because it is also useful with op=. (It has also been added for op- even though it duplicates x, in this case, because it is intuitive and easier to explain.)


1 man 1 chmod
2 info '(coreutils)Conditional Executability'

Cristian Ciupitu

Posted 2014-05-23T07:37:14.463

Reputation: 4 515

Yeah, right, I could never adjust to the fact that nowadays many commands (cp, chmod...) have the -R flag... Once upon a time find was the only instrument to do this recursively. – MariusMatutiae – 2014-05-23T08:44:44.260

2

If you want to do it recursively, i.e., to directories within directories within directories, the command to use is:

 find /path/to/starting/directory -type d -exec chmod +x {} \;

This locates all and only subdirectories (-type d flag) of the directory /path/to/starting/directory, and then performs the required change of execute permission to each one of them. The space before \; is mandatory.

MariusMatutiae

Posted 2014-05-23T07:37:14.463

Reputation: 41 321

0

Have you tried something like:

chmod +x $(ls -p | grep /), this adds the execution permission ton only directories

and if you would like to give execution permission to files and directories, just do :

chmod +x * and to delete permissions to execute to files try something like this :

chmod -x *.*

Hoping it helps

BigFoot

Posted 2014-05-23T07:37:14.463

Reputation: 45

If using Bash, */ can also be used to match directories. – Cristian Ciupitu – 2014-05-23T08:35:38.890

1

Please never recommend parsing ls. This will fail even in the simplest of cases where the directory names contain whitespace.

– terdon – 2014-05-23T15:00:11.883

@terdon, there's also Why not parse ls?

– Cristian Ciupitu – 2014-05-23T23:23:11.440

@CristianCiupitu yes, I know. Mine is the third most upvoted answer there :). – terdon – 2014-05-24T02:17:02.867

Okay, sorry then and thanks for the advice :) – BigFoot – 2014-05-24T12:36:19.340

0

Try this:

find . -mindepth 1  -print0 | while IFS= read -r -d '' file; do
    if [ -d "$file" ]; then chmod 750 "$file";
    else chmod 640 "$file"; fi
done

Explanation

  • -mindepth 1 : That's so find wont match the current directory, ..
  • -print0 : prints null-separated output. This ensures that we deal correctly with fioles containing newlines.
  • while IFS= : setting IFS to the empty string turns off word splitting. Necessary for file/directory names with whitespace.
  • read -r -d '' : this reads each line into $file but the -r ensures we don't treat \ specially (in case there are some in your file names) and -d '' sets the delimiter to the null string so we parse the output of find correctly and can deal with fiole names containing newlines.
  • if [ -d "$file" ]; then chmod 750 "$file"; : If the $file is a directory ([ -d "$file" ], set its permissions to drwxr-x---.
  • else chmod 640 "$file"; fi : if it's not a directory, set them to -rw-r-----.

terdon

Posted 2014-05-23T07:37:14.463

Reputation: 45 216

0

chmod -R u=rwX,g=rX,o= .

The uppercase X means that it is only set if it's already set somewhere else. Since all your directories are already executable for the user, they will also be made executable for groups. Since files are not executable for the user, they will not be made executable for groups either.

Using chmod +X will have roughly the same effect, except that, when it gives execute rights, it will give execute rights to user, group and other.

jornane

Posted 2014-05-23T07:37:14.463

Reputation: 977

0

Thanks for the answers. I found that in order to assign execution permissions only to directories, it is necessary to use the capital X permission.

So the command would be as follows:

chmod -R a-rwx,u=rwX,g=rX .

http://www.manpagez.com/man/1/chmod/

(It took me a while to find that, so I wanted to share with everyone. Now I guess that this question will be indexed on Google for the next person who wants to know)

Daniel

Posted 2014-05-23T07:37:14.463

Reputation: 238