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 configuration640rw-r-----Owner-managed file readable by a service group644rw-r--r--Publicly readable non-secret file750rwxr-x---Private application directory or executable755rwxr-xr-xWorld-traversable directory or public executable700rwx------Private directoryUse 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 sortLowercase 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 sortGNU 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")" = 770Verification 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.