As a quick reference, here’s why [.inline-code]chmod[.inline-code] recursion is tricky:
The short (and wrong) answer to "how do I run chmod recursively" is "with the [.inline-code]-R[.inline-code] switch." For example [.inline-code]chmod -R 644 *[.inline-code] will indeed change everything to [.inline-code]-rw-r--r--[.inline-code] 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-flag]Using [.inline-code]find[.inline-code] with [.inline-code]-exec[.inline-code][#using-find-with-exec-flag]
The correct answer to recursive [.inline-code]chmod[.inline-code] is to use [.inline-code]find[.inline-code] with the [.inline-code]-exec[.inline-code] flag. This will let you target files and directories by type, name, extension, etc., and apply permissions selectively to matching files and directories.
With [.inline-code]find[.inline-code] you can filter out the specific files/types you want to affect, and then use the [.inline-code]-exec[.inline-code] flag to perform a command on the matched files, in this case [.inline-code]chmod[.inline-code]. The [.inline-code]find[.inline-code] command is recursive by default, including all subdirectories (and their subdirectories). You can limit how deep the command traverses with the [.inline-code]-depth n[.inline-code] flag.
To affect only the _files_ in the current directory and its subdirectories, we'll use [.inline-code]find -type f[.inline-code] ("find type file") and apply standard file permissions of 644 to the files:
The [.inline-code]{}[.inline-code] 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. [.inline-code]-exec[.inline-code] commands must end with [.inline-code]\;[.inline-code].
To do the same thing with directories, but apply 755 permissions:
With [.inline-code]find[.inline-code], you can also target files by name, creation date, owner, and a host of other options, allowing you to target operations like [.inline-code]chmod[.inline-code] very precisely.
[#a-lot-of-files]When you have a lot of files...[#a-lot-of-files]
To speed up the process when working on a large number of files or directories, you can use [.inline-code]-print0[.inline-code] to send a null-separated list, piping it to [.inline-code]xargs -0[.inline-code] to execute a command on each entry.
Note that with the [.inline-code]find[.inline-code] commands listed above, we're using [.inline-code].[.inline-code] (current directory) as our base for finding files. You can insert any path in place of the [.inline-code].[.inline-code] to execute the find from that base, e.g. [.inline-code]/var/www[.inline-code] or whatever you need.
So, to summarize, don't use [.inline-code]chmod -R[.inline-code] in almost any circumstance. Rather, use [.inline-code]find ... -exec chmod ...[.inline-code] to apply permissions selectively to files and directories based on their type or other parameters.