chmod: Symbolic and Octal Permissions
chmod changes mode bits; it does not determine what the
correct policy should be. Good permission work starts from an
intended access contract, applies the smallest change, and verifies
the resulting behavior. This lesson covers both symbolic and octal
forms, including the recursion hazards that commonly break
deployments.
Learning objectives
By the end of this lesson
-
Construct symbolic mode clauses with
u,g,o,a,+,-, and=. - Translate common modes between symbolic and octal notation.
-
Use conditional execute
Xand--referenceappropriately. -
Avoid unsafe
chmod -Rpatterns by treating files and directories separately. - Implement and verify a deployment-tree permission policy.
1. Symbolic chmod expresses a relative policy change
A symbolic clause has the conceptual form
who operation permissions. The who set is
owner (u), group (g), other
(o), or all (a). The operation adds
(+), removes (-), or assigns exactly
(=) the selected bits.
flowchart LR W["Who?
u g o a"] --> O["Operation?
+ - ="] O --> B["Bits?
r w x X s t"] B --> M["Modify the existing mode"] M --> V["Verify resulting access"]
file="$HOME/devops-academy/linux/chapter06/lesson02/example.txt"
mkdir -p -- "$(dirname -- "$file")"
printf 'release metadata
' > "$file"
chmod u=rw,go=r -- "$file" # exact: 0644
chmod g+w -- "$file" # add group write: 0664
chmod o-r -- "$file" # remove other read: 0660
chmod a-rwx,u=rw,g=r -- "$file" # explicit reset: 0640
stat -c '%A %a %n' -- "$file"
When who is omitted, the current umask influences which
classes are changed. Production automation should normally state the
classes explicitly so behavior does not depend on the invoking
environment.
2. Octal modes assign an exact bit pattern
An octal triplet assigns owner, group, and other permissions. Each digit is the sum of read 4, write 2, and execute 1. A leading fourth digit represents special bits, covered in Lesson 4.
600rw-------Private secret or user configuration
640rw-r-----Owner-managed file readable by a service group
644rw-r--r--Publicly readable non-secret file
750rwxr-x---Private application directory or executable
755rwxr-xr-xWorld-traversable directory or public executable
700rwx------Private directory
Use octal when you want a known final mode. Use symbolic clauses when you want to preserve unrelated bits while adding or removing a specific capability.
3. Conditional execute X protects ordinary files
Symbolic X adds execute only to directories and to
files that already have at least one execute bit. It is useful when
fixing traversal across a mixed tree without turning every data file
into an executable.
tree="$HOME/devops-academy/linux/chapter06/lesson02/tree"
mkdir -p -- "$tree/bin" "$tree/config"
printf '#!/usr/bin/env bash
echo ok
' > "$tree/bin/check"
printf 'port=8080
' > "$tree/config/app.conf"
chmod 700 -- "$tree/bin/check"
chmod 600 -- "$tree/config/app.conf"
# Add group read everywhere and group traversal where appropriate.
chmod -R g+rX -- "$tree"
find "$tree" -printf '%M %m %p
' | LC_ALL=C sort
Lowercase x would add execute to every selected object.
That can mask packaging errors, expand attack surface, and confuse
tools that discover executables by mode.
4. Recursive changes require an object-type policy
A common failure is assigning one mode to an entire application
tree. Directories need execute for traversal; ordinary configuration
files usually do not. Use find with explicit type
predicates when the final modes differ.
release="$HOME/devops-academy/linux/chapter06/lesson02/release"
# Preview targets before changing anything.
find "$release" -type d -print
find "$release" -type f -print
# Apply separate directory and file policies.
find "$release" -type d -exec chmod 750 -- {} +
find "$release" -type f -exec chmod 640 -- {} +
find "$release/bin" -type f -exec chmod 750 -- {} +
# Verify exact resulting modes.
find "$release" -printf '%y %m %u:%g %p
' | LC_ALL=C sort
GNU chmod offers recursive options and symlink
handling, but portability and traversal behavior vary. Avoid
following untrusted symlinks during bulk permission repair. Work on
a bounded root and verify with find -xdev when crossing
mounted filesystems would be dangerous.
5. Reference modes reduce duplicated policy literals
chmod --reference=MODEL TARGET copies the mode from a
known-good object. This is useful when a package or deployment
creates a canonical file and related files must match it.
model="$HOME/devops-academy/linux/chapter06/lesson02/model.conf"
target="$HOME/devops-academy/linux/chapter06/lesson02/generated.conf"
printf 'model=true
' > "$model"
printf 'generated=true
' > "$target"
chmod 640 -- "$model"
chmod --reference="$model" -- "$target"
stat -c '%A %a %n' -- "$model" "$target"
The reference copies mode bits, not owner or group. Ownership is a separate control plane covered in Lesson 3.
6. Hands-on lab: enforce a release permission contract
set -eu
lab="$HOME/devops-academy/linux/chapter06/lesson02"
release="$lab/release"
rm -rf -- "$release"
mkdir -p -- "$release/bin" "$release/config" "$release/logs"
printf '#!/usr/bin/env bash
printf "service=ready\n"
' > "$release/bin/service-check"
printf 'listen=127.0.0.1:8080
' > "$release/config/service.conf"
printf 'initial log
' > "$release/logs/service.log"
printf 'release notes
' > "$release/README.txt"
# Begin from intentionally inconsistent modes.
chmod 777 -- "$release/bin/service-check"
chmod 666 -- "$release/config/service.conf" "$release/README.txt"
chmod 777 -- "$release/logs"
# Contract: directories 750, ordinary files 640, executable files 750,
# writable runtime directory 770.
find "$release" -type d -exec chmod 750 -- {} +
find "$release" -type f -exec chmod 640 -- {} +
chmod 750 -- "$release/bin/service-check"
chmod 770 -- "$release/logs"
find "$release" -printf '%y %m %p
' | LC_ALL=C sort > "$lab/mode-report.txt"
cat -- "$lab/mode-report.txt"
"$release/bin/service-check"
test "$(stat -c %a -- "$release/config/service.conf")" = 640
test "$(stat -c %a -- "$release/logs")" = 770
Verification checklist
7. Common chmod mistakes
chmod -R 777
This removes meaningful boundaries and often introduces executable bits where they do not belong.
One mode for files and directories
The execute bit has different semantics. Separate policies by object type.
Using relative changes in idempotent automation
g+w preserves unknown state. An exact mode is often
clearer when configuration management owns the object.
Skipping verification
A successful command may have targeted the wrong tree or preserved unexpected special bits.
8. Knowledge check
Question 1. What is the difference between
chmod g+w and chmod g=rw?
g+w adds group write while preserving the group’s
other bits. g=rw assigns exactly read and write to
the group class, removing group execute if present.
Question 2. Why is g+X safer than
g+x on a mixed directory tree?
Question 3. Why should recursive permission automation separate files from directories?
9. Summary
chmod implements a permission policy through relative
symbolic clauses or exact octal modes. Safe automation names the
affected classes, treats files and directories separately, uses
capital X deliberately, bounds recursive operations,
and verifies final state with stat or
find.
10. Further reading
-
GNU Coreutils manual: mode structure and
chmodinvocation. -
Linux man-pages:
chmod(2),fchmodat(2), andinode(7). - GNU Findutils manual for bounded type-specific bulk operations.
- POSIX file modes and symbolic mode notation.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.