TechEarl

How to chmod Recursively (Files vs Directories)

Apply permissions down a whole tree with chmod -R, and the capital-X trick that sets execute on directories but leaves regular files alone.

Ishan Karunaratne⏱️ 4 min readUpdated
Share thisCopied
Apply permissions down a directory tree with chmod -R, and the capital-X flag that sets execute on directories but not on regular files.

chmod -R applies a mode to a directory and everything inside it:

bash
chmod -R u+rwX,go-w ~/proj
Terminal showing chmod -R u+rwX,go-w on a project directory, then ls -lR confirming the directory keeps execute while regular files do not gain it.
-R walks the whole tree; the capital X adds execute only to directories and already-executable files, not to plain files.

The trap: chmod -R 755 breaks nothing, chmod -R 644 breaks everything

The naive recursive command is chmod -R 755 dir or chmod -R 644 dir. The second is a disaster: it strips the execute bit from directories, and a directory without execute cannot be entered. Suddenly you cannot cd into your own folders or reach the files inside, even though you can see the names.

The reason is that numeric modes apply the same nine bits to files and directories alike, but directories need the execute bit and regular files usually should not have it.

The fix: capital X

chmod has a special mode X (capital) that means "execute, but only for directories and files that are already executable". It is exactly what recursive operations want:

bash
# Owner full access; group/other read; directories stay traversable; plain files don't become executable
chmod -R u=rwX,go=rX ~/proj

X adds the execute bit to directories (so they stay enterable) and to files that already had execute (so scripts keep working), but it does not make every text file executable. This is the single most useful chmod fact most people never learn.

Better still: target files and directories separately

When you want precise control, use find to split the two:

bash
find ~/proj -type d -exec chmod 755 {} +     # directories: 755
find ~/proj -type f -exec chmod 644 {} +     # files: 644

-type d matches directories, -type f matches regular files, so each gets the mode that actually fits it. This is the bulletproof version for a web root or a release artifact. For more on the find side, see find files by owner, group, or permission.

FAQ

See also

Sources

Authoritative references this article was fact-checked against.

TagsLinuxchmodFile PermissionsRecursiveSystem Administration

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

How to grep Recursively Through a Directory

grep -r 'pattern' . searches every file under a directory tree. The catch is the path argument people forget, the -r vs -R symlink difference, and the unfiltered crawl into node_modules and .git. The flag reference, the --include and --exclude-dir filters, the macOS BSD vs GNU gaps, and when to reach for ripgrep or git grep instead.

How to Exclude Files and Directories from grep

grep does not read .gitignore, so skipping node_modules, .git, and build output is on you. The flags that do it: --exclude for filename globs, --exclude-dir for whole directories, --include for the inverse, --exclude-from to read the list from a file, plus the find -prune fallback for older macOS grep.

How to Import a CSV File Into MySQL

Import a CSV into MySQL using LOAD DATA INFILE, LOAD DATA LOCAL INFILE, or the mysqlimport command. Covers header rows, encoding, the FILE privilege, and broken CSVs.