How to run chmod recursively
Brett Terpstra
Principal Developer, Oracle
Published: 11/30/2023
As a quick reference, here’s why chmod recursion is tricky:
# NOT what you want, because files and directories require separate treatment
chmod -R 644 *
# The correct way:
# Set _files_ in the current directory and its subdirectories to 644
find . -type f -exec chmod 644 "{}" \;
# Set _directories_ in the current directory to 755
find . -type d -exec chmod 755 "{}" \;
Run in Warp
The short (and wrong) answer to "how do I run chmod recursively" is "with the -R switch." For example chmod -R 644 * will indeed change everything to -rw-r--r-- permissions, but that's almost _never_ what you actually want to do. Even at the most basic level, directories and files need different permissions (755 and 644, respectively), and setting both to the same permissions will result in problems.
Using find with -exec
The correct answer to recursive chmod is to use find with the -exec flag. This will let you target files and directories by type, name, extension, etc., and apply permissions selectively to matching files and directories.
With find you can filter out the specific files/types you want to affect, and then use the -exec flag to perform a command on the matched files, in this case chmod. The find command is recursive by default, including all subdirectories (and their subdirectories). You can limit how deep the command traverses with the -depth n flag.
To affect only the _files_ in the current directory and its subdirectories, we'll use find -type f ("find type file") and apply standard file permissions of 644 to the files:
$ find . -type f -exec chmod 644 "{}" \;
Run in Warp
The {} is replaced with each matching file, applying the exec command one at a time, and the quotes allow for spaces and other reserved characters in the filename. -exec commands must end with \;.
To do the same thing with directories, but apply 755 permissions:
$ find . -type d -exec chmod 755 "{}" \;
Run in Warp
With find, you can also target files by name, creation date, owner, and a host of other options, allowing you to target operations like chmod very precisely.
When you have a lot of files...
To speed up the process when working on a large number of files or directories, you can use -print0 to send a null-separated list, piping it to xargs -0 to execute a command on each entry.
$ find . -type d -print0 | xargs -0 chmod 755
$ find . -type f -print0 | xargs -0 chmod 644
Run in Warp
Note that with the find commands listed above, we're using . (current directory) as our base for finding files. You can insert any path in place of the . to execute the find from that base, e.g. /var/www or whatever you need.
So, to summarize, don't use chmod -R in almost any circumstance. Rather, use find ... -exec chmod ... to apply permissions selectively to files and directories based on their type or other parameters.
Written by
Brett Terpstra
Principal Developer, Oracle
Filed Under
Related Articles
Bash If Statement
Learn how to use the if statement in Bash to compare multiple values and expressions.
Bash While Loop
Learn how to use and control the while loop in Bash to repeat instructions, and read from the standard input, files, arrays, and more.
POST JSON Data With Curl
How to send valid HTTP POST requests with JSON data payloads using the curl command and how to avoid common syntax pitfalls. Also, how to solve the HTTP 405 error code.
Use Cookies With cURL
Learn how to store and send cookies using files, hard-coded values, environment variables with cURL.
Loop Through Files in Directory in Bash
Learn how to iterate over files in a directory linearly and recursively using Bash and Python.
How To Use sudo su
A quick overview of using sudo su
Generate, Sign, and View a CSR With OpenSSL
Learn how to generate, self-sign, and verify certificate signing requests with `openssl`.
How to use sudo rm -rf safely
We'll help you understand its components
Run Bash Shell In Docker
Start an interactive shell in Docker container
Curl Post Request
Use cURL to send data to a server
Reading User Input
Via command line arguments and prompting users for input
Bash Aliases
Create an alias for common commands