Cheatsheets

Chmod

Chmod

Complete chmod reference with numeric and symbolic permissions, special bits, directory permissions, and practical examples for managing file access

8 Categories 24 Sections 50 Examples
Chmod Permissions File Permissions Directory Permissions SUID SGID Sticky Bit Linux

Getting Started

Introduction to chmod and permission fundamentals

What is Chmod

Understanding chmod and file permissions in Unix-like systems

Chmod overview and permissions concept

File permissions are displayed in ls -l output. The first 10 characters show type and permissions (rwxrwxrwx format).

Code
Terminal window
# Chmod stands for: change mode
# Used to change file and directory permissions
# Basic syntax: chmod [options] mode file
# Where mode can be:
# - Octal notation: 755 (4 digits maximum)
# - Symbolic notation: u+x, g-w, o=rx
# Permission components:
# user (u), group (g), other (o), all (a)
# read (r=4), write (w=2), execute (x=1)
# Key features:
# - Change owner/group/other permissions
# - Apply to files and directories
# - Recursive modification with -R
# - Special bits: setuid (4), setgid (2), sticky (1)
Execution
Terminal window
ls -la /tmp/testfile.txt 2>/dev/null || touch /tmp/testfile.txt && ls -la /tmp/testfile.txt
Output
Terminal window
-rw-r--r-- 1 user group 0 Feb 28 10:00 /tmp/testfile.txt
  • First character indicates file type (- for file, d for directory, l for link)
  • Next 9 characters are permissions: 3 for user, 3 for group, 3 for other
  • Read files before changing permissions
  • Test changes on non-critical files first

Understanding permission string format

The stat command displays permissions in both octal (644) and symbolic (-rw-r--r--) formats.

Code
Terminal window
# Permission string format: -rwxrwxrwx
# Position 1: File type (- = file, d = directory, l = link, etc.)
# Positions 2-4: User (owner) permissions
# Positions 5-7: Group permissions
# Positions 8-10: Other permissions
# r (read) = 4
# w (write) = 2
# x (execute) = 1
# Examples:
# -rw-r--r-- = file, user: rw (6), group: r (4), other: r (4) = 644
# drwxr-xr-x = dir, user: rwx (7), group: rx (5), other: rx (5) = 755
# -rwx------ = file, user: rwx (7), group: none (0), other: none (0) = 700
Execution
Terminal window
stat -c "%a %A %n" /tmp/testfile.txt
Output
Terminal window
644 -rw-r--r-- /tmp/testfile.txt
  • Octal notation is more concise for scripts
  • Symbolic notation is more readable for humans
  • Both formats accomplish the same result
  • 644 is common for files, 755 for directories

Installation and Setup

Verifying chmod availability and getting started

Verify chmod installation

Chmod is a POSIX standard utility, always available on Unix-like systems at /bin/chmod or /usr/bin/chmod.

Code
Terminal window
# Check if chmod is installed
which chmod
# Display chmod version (man page)
chmod --version 2>/dev/null || man chmod | head -20
# Show chmod help
man chmod | head -30
# Quick help
chmod --help 2>/dev/null | head -20
Execution
Terminal window
which chmod
Output
Terminal window
/bin/chmod
  • Chmod is pre-installed on all Linux and Unix systems
  • Part of coreutils package
  • Available in POSIX-compliant systems
  • No additional installation needed

Access chmod man pages for detailed reference

The help and man pages provide comprehensive chmod reference documentation and usage examples.

Code
Terminal window
# Read full chmod manual
man chmod
# View specific sections
man chmod | grep -A 10 "DESCRIPTION"
# Search for specific permission
man chmod | grep -i "setuid"
# View examples
man chmod | grep -A 5 "EXAMPLES"
Execution
Terminal window
chmod --help 2>&1 | head -15
Output
Terminal window
Usage: chmod [OPTION]... MODE[,MODE]... FILE...
or: chmod [OPTION]... OCTAL-MODE FILE...
or: chmod [OPTION]... --reference=RFILE FILE...
Change the mode of each FILE to MODE.
-c, --changes like -v but report only when a change is made
-f, --silent, --quiet suppress most error messages
-v, --verbose output a diagnostic for every file processed
-R, --recursive change files and directories recursively
--reference=RFILE use RFILE's mode instead of MODE values
  • Man pages contain complete descriptions of all options
  • Help flag varies between GNU and BSD versions
  • Man page is most authoritative reference
  • Online documentation available at man7.org

Basic Permissions

Understanding octal and symbolic notation for file permissions

Octal Notation

Using numerical octal format for specifying permissions

Understanding octal notation basics

Chmod 644 sets owner read+write, group read, other read permissions (6+4+4=644).

Code
Terminal window
# Octal notation uses 3-4 digits
# Each digit represents a category:
# Position 1 (optional): Special bits (setuid=4, setgid=2, sticky=1)
# Position 2: User/Owner permissions
# Position 3: Group permissions
# Position 4: Other permissions
# Each permission has a value:
# r (read) = 4
# w (write) = 2
# x (execute) = 1
# Examples of octal modes:
# 644 = rw-r--r-- (file: owner rw, group r, other r)
# 755 = rwxr-xr-x (directory: owner rwx, group rx, other rx)
# 700 = rwx------ (private: only owner can access)
# 777 = rwxrwxrwx (full: all can read/write/execute)
Execution
Terminal window
touch /tmp/testfile.txt && chmod 644 /tmp/testfile.txt && ls -l /tmp/testfile.txt
Output
Terminal window
-rw-r--r-- 1 user group 0 Feb 28 10:00 /tmp/testfile.txt
  • 644 is standard for regular files
  • 755 is standard for directories
  • 600 is for private files only owner can access
  • 777 is rarely needed and less secure

Common octal permission modes

Different octal modes produce different permission strings. 644 allows owner write, 755 allows execution, 700 restricts access to owner.

Code
Terminal window
# Commonly used octal modes:
# 755: rwxr-xr-x (directories, executables)
# Owner: full access, Group/Other: read and execute only
# 644: rw-r--r-- (regular files)
# Owner: read and write, Group/Other: read only
# 700: rwx------ (private - owner only)
# Only owner has all permissions
# 600: rw------- (private file - owner only)
# Owner read/write, no access for group/other
# 775: rwxrwxr-x (group-writable)
# Owner/Group have full access, other read/execute
# 666: rw-rw-rw- (all can read/write)
# All users can read and write (uncommon, less secure)
# 444: r--r--r-- (read-only for all)
# All users can read, none can write/execute
Execution
Terminal window
cd /tmp && touch file_644 file_755 file_700 && chmod 644 file_644 && chmod 755 file_755 && chmod 700 file_700
ls -la file_* | awk '{print $1, $9}'
Output
Terminal window
-rw-r--r-- file_644
-rwxr-xr-x file_755
-rwx------ file_700
  • 644 and 755 are most commonly used
  • 700 for sensitive files (private keys, config)
  • 775 for collaborative team files
  • 666 and 777 rarely used due to security concerns

Symbolic Notation

Using symbolic format (u/g/o/a ±= rwxXst) for permissions

Understanding symbolic notation syntax

u+x adds execute permission for the user. Starting from 644 (-rw-r--r--), it becomes 744 (-rwxr--r--).

Code
Terminal window
# Symbolic notation syntax: [ugoa]*([-+=][perms...]...)
# Who: u=user, g=group, o=other, a=all (default)
# Operator: + (add), - (remove), = (set exactly)
# Permissions: r (read), w (write), x (execute)
# : X (execute if already executable)
# : s (setuid/setgid), t (sticky)
# Examples:
# u+x Add execute for user
# g-w Remove write from group
# o= Remove all permissions from other
# a+r Add read for all
# u+x,g+x Multiple changes in one command
# g=r Set group to read-only
# a= Remove all permissions for all users
Execution
Terminal window
touch /tmp/sym_test.txt && chmod u+x /tmp/sym_test.txt && ls -l /tmp/sym_test.txt
Output
Terminal window
-rwxr--r-- 1 user group 0 Feb 28 10:00 /tmp/sym_test.txt
  • Symbolic notation builds on existing permissions
  • Use + to add, - to remove, = to set exactly
  • Easier to remember than octal for common changes
  • More readable in scripts and documentation

Common symbolic notation examples

u+w,g+w adds write permission for both user and group. Multiple changes are separated by commas.

Code
Terminal window
# Add write permission for user
chmod u+w file.txt
# Remove execute from all
chmod a-x file.sh
# Set group to read-only
chmod g=r file.txt
# Add execute if already readable
chmod u+X file.txt
# Remove all permissions except user read
chmod a-rwx,u+r file.txt
# Make readable by all
chmod a+r file.txt
# Make directory traversable by group
chmod g+x directory
# Make file non-writable by anyone
chmod a-w file.txt
# Give user all, group read/execute, other nothing
chmod u=rwx,g=rx,o= file.txt
Execution
Terminal window
touch /tmp/sym_demo.txt && chmod 644 /tmp/sym_demo.txt
echo "Before: $(ls -l /tmp/sym_demo.txt | awk '{print $1}')"
chmod u+w,g+w /tmp/sym_demo.txt
echo "After: $(ls -l /tmp/sym_demo.txt | awk '{print $1}')"
Output
Terminal window
Before: -rw-r--r--
After: -rw-rw-r--
  • Chain multiple changes with commas
  • No spaces between changes
  • More readable than octal for humans
  • Better for documenting intent in scripts

Understanding rwx Permissions

Detailed explanation of read, write, and execute permissions

Read permission (r) explained

Read permission (444) allows viewing file contents but prevents modification or execution.

Code
Terminal window
# Read permission (r) = 4
# For files: Allows reading/viewing file contents
# For directories: Allows listing directory contents with ls
# File with read permission:
# Can: cat, less, grep, copy the file
# Cannot: run/execute file, modify file
# Directory with read permission:
# Can: list files with ls
# Cannot: enter directory (cd), access files
# Note: Need execute for directory access
# Example:
# r--r--r-- (444)
# File is readable by all, not writable
Execution
Terminal window
touch /tmp/read_test.txt && echo "test content" > /tmp/read_test.txt && chmod 444 /tmp/read_test.txt
echo "=== File status (r--r--r--) ===" && ls -l /tmp/read_test.txt
echo "=== Can read file ===" && cat /tmp/read_test.txt
Output
Terminal window
=== File status (r--r--r--) ===
-r--r--r-- 1 user group 12 Feb 28 10:00 /tmp/read_test.txt
=== Can read file ===
test content
  • Read is required to view file or list directory
  • For directories, read alone doesn't allow cd
  • For files, read doesn't allow execution
  • Read-only files cannot be deleted by non-owners

Write permission (w) explained

Write permission (666) allows modification of file contents. Without it, the file is read-only.

Code
Terminal window
# Write permission (w) = 2
# For files: Allows modifying/deleting file contents
# For directories: Allows creating/deleting files in directory
# File with write permission:
# Can: modify, overwrite, append, truncate file
# Cannot: if no read, cannot see current contents
# Directory with write permission:
# Can: create new files, delete existing files
# Can: rename files, modify directory contents
# Note: Still needs execute to access files in it
# Example:
# -w--w--w- (222)
# All users can write/modify
Execution
Terminal window
touch /tmp/write_test.txt && chmod 644 /tmp/write_test.txt && echo "original" > /tmp/write_test.txt
echo "=== Start content ===" && cat /tmp/write_test.txt
chmod 666 /tmp/write_test.txt && echo "modified" >> /tmp/write_test.txt
echo "=== After chmod 666 and write ===" && cat /tmp/write_test.txt
Output
Terminal window
=== Start content ===
original
=== After chmod 666 and write ===
original
modified
  • Write requires modify/delete permission
  • Write on file allows content changes
  • Write on directory allows creating/deleting files
  • Owner can delete own file even without write with write directory

Execute permission (x) explained

Execute permission on directories (755) allows entering and accessing the directory. For files, it allows execution.

Code
Terminal window
# Execute permission (x) = 1
# For files: Allows running/executing file (scripts, binaries)
# For directories: Allows entering directory (cd), accessing files/subdirs
# File with execute permission:
# Can: run if it's a script or binary
# Still needs read to execute scripts (interpreter needs to read)
# Directory with execute permission:
# Can: cd into directory, access contents
# Core permission needed for directory access
# Note: Still needs read to list, execute to access
# Example:
# rwxr-xr-x (755) - directory mode
# Allows owner full, group/other can view and access
Execution
Terminal window
mkdir -p /tmp/exec_test && chmod 755 /tmp/exec_test && touch /tmp/exec_test/file.txt
echo "=== Directory with execute (755) ===" && ls -ld /tmp/exec_test
echo "=== Can access directory and list contents ===" && ls /tmp/exec_test
Output
Terminal window
=== Directory with execute (755) ===
drwxr-xr-x 2 user group 4096 Feb 28 10:00 /tmp/exec_test
=== Can access directory and list contents ===
file.txt
  • Execute on directory = can cd into it
  • Execute on file = can run it (if read also present for scripts)
  • Directories typically get 755, files 644 or 755
  • Execute bit essential for directory traversal

User/Group/Other Permissions

Managing permissions for owner, group, and other users

User Permissions

Setting and managing owner/user permissions

Setting user-only permissions

Chmod 600 (u=rw,g=,o=) allows owner read and write, no access for group or other.

Code
Terminal window
# Set permissions for owner/user only
# u=rwx (user has all permissions, group/other have none)
# Common user-only patterns:
# u=rwx,g=,o= or 700 - owner full access only
# u=rw (read/write for owner)
# u+x (add execute for owner)
# u-w (remove write from owner)
# Examples:
chmod u=rwx file.sh # owner full access
chmod 700 private.key # private file - owner only
chmod u+x script.sh # make script executable by owner
chmod u-w readonly.txt # make file read-only for owner
Execution
Terminal window
touch /tmp/user_perm.txt && chmod 600 /tmp/user_perm.txt && ls -l /tmp/user_perm.txt
Output
Terminal window
-rw------- 1 user group 0 Feb 28 10:00 /tmp/user_perm.txt
  • 600 is appropriate for sensitive files
  • 700 for directories only owner can access
  • User permissions are inherited by file creator
  • Owner can change permissions only on own files (unless root)

Adding and removing user permissions

User permissions can be modified individually. u+x adds execute, u-r removes read from the owner.

Code
Terminal window
# Add execute permission for user
chmod u+x file.sh
# Remove write permission for user
chmod u-w file.txt
# Add read and execute
chmod u+rx file
# Remove all user permissions
chmod u= file.txt
# Reset user to basic read/write
chmod u=rw file.txt
# Add write back to user
chmod u+w file.txt
Execution
Terminal window
touch /tmp/user_mod.txt && chmod 644 /tmp/user_mod.txt
echo "Initial: $(ls -l /tmp/user_mod.txt | awk '{print $1}')"
chmod u+x /tmp/user_mod.txt
echo "After u+x: $(ls -l /tmp/user_mod.txt | awk '{print $1}')"
chmod u-r /tmp/user_mod.txt
echo "After u-r: $(ls -l /tmp/user_mod.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rw-r--r--
After u+x: -rwxr--r--
After u-r: --wxr--r--
  • Changes are additive with +, subtractive with -
  • = sets exactly what you specify
  • Other permissions unchanged unless specified
  • Always verify with ls -l after changes

Group Permissions

Managing group permissions for shared files

Setting group permissions

Chmod 640 (u=rw,g=r,o=) allows owner read/write and group read, no access for others.

Code
Terminal window
# Set permissions for group members
# g=rx (group can read and execute)
# g+w (add write for group)
# g-x (remove execute from group)
# Common group patterns:
# g=r (group read-only)
# g=rx (group read and execute - typical for directories)
# g=rw (group read and write - for shared files)
# g= (remove all group permissions)
# Examples:
chmod g=r file.txt # group read-only
chmod g+w file.txt # add write for group
chmod g-x directory # remove execute from group
chmod g= file.txt # remove all group permissions
Execution
Terminal window
touch /tmp/group_perm.txt && chmod 640 /tmp/group_perm.txt && ls -l /tmp/group_perm.txt
Output
Terminal window
-rw-r----- 1 user group 0 Feb 28 10:00 /tmp/group_perm.txt
  • 640 is common for files shared with group
  • 750 is common for directories shared with group
  • Group must include relevant users
  • More restrictive than world-readable
  • Good for team collaboration

Collaborative file sharing with group permissions

g+w adds write permission for the group. This allows group members to modify the file.

Code
Terminal window
# File shared with group, readable and writable by all group members
chmod g+rw file.txt
# Directory shared with group, all can access and add files
chmod g+rw directory/
chmod g+x directory/
# Make group permissions match user
chmod g=u file.txt
# Remove write from group
chmod g-w file.txt
# Set standard collaboration mode
chmod g=rx directory/
# Add group permissions without changing others
chmod g+w file.txt
Execution
Terminal window
touch /tmp/collab.txt && chmod 644 /tmp/collab.txt
echo "Initial: $(ls -l /tmp/collab.txt | awk '{print $1}')"
chmod g+w /tmp/collab.txt
echo "After g+w: $(ls -l /tmp/collab.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rw-r--r--
After g+w: -rw-rw-r--
  • g+w enables group write access
  • Useful for shared project files
  • Verify group membership with id command
  • Set before sharing with team members

Other Permissions

Managing permissions for all other users

Setting permissions for others

Chmod 600 removes all permissions from group and other. Only the owner can access the file.

Code
Terminal window
# Set permissions for other/world users
# o=r (other can only read)
# o+x (add execute for other - allow others to access)
# o= (remove all permissions from other/world)
# Common patterns:
# o= (completely private, except user/group)
# o=r (world readable)
# o=rx (world readable and executable - common for web)
# o+r (add read for others)
# Examples:
chmod o=r file.txt # world readable only
chmod o= file.txt # private, no world access
chmod o+r file.txt # add read for others
chmod o-r file.txt # remove read from others
Execution
Terminal window
touch /tmp/other_perm.txt && echo "content" > /tmp/other_perm.txt && chmod 600 /tmp/other_perm.txt && ls -l /tmp/other_perm.txt
Output
Terminal window
-rw------- 1 user group 0 Feb 28 10:00 /tmp/other_perm.txt
  • 600 is for completely private files
  • Others have no access at all
  • Appropriate for sensitive data
  • Prevents accidental exposure

World-readable and accessible files

o+r adds read permission for others. The file becomes world-readable (644).

Code
Terminal window
# Make file world-readable
chmod o+r file.txt
# Make directory world-accessible with readable contents
chmod o+rx directory/
# Make web content accessible
chmod o=rx script.sh
# Add world-accessible read
chmod a+r file.txt (adds read for all: user, group, other)
# Remove world access entirely
chmod o= file.txt
# World-readable, user/group writable
chmod 664 file.txt
Execution
Terminal window
touch /tmp/world.txt && chmod 640 /tmp/world.txt
echo "Initial: $(ls -l /tmp/world.txt | awk '{print $1}')"
chmod o+r /tmp/world.txt
echo "After o+r: $(ls -l /tmp/world.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rw-r-----
After o+r: -rw-r--r--
  • o+r makes file readable by any user
  • Useful for public files and web content
  • Be careful with sensitive data
  • Web files typically need o=r or o=rx

All Permissions (a)

Managing permissions for all users at once

Setting permissions for all users

a+r adds read permission for all users. Starting from 700, it becomes 744 (rwxr--r--).

Code
Terminal window
# Set permissions for all users (user, group, other)
# a=r (read-only for everyone)
# a=rx (read and execute for everyone)
# a+r (add read for all)
# a-w (remove write from all)
# a= (remove all permissions - be careful!)
# Common patterns:
# a=r (world readable, no write/execute)
# a=rx (world readable and executable)
# a-w (remove write from everyone)
# a+r (add read for everyone)
# Examples:
chmod a+r file.txt # readable by all
chmod a-w file.txt # no one can write
chmod a+x file.sh # executable by all
chmod a= file.txt # remove all permissions
Execution
Terminal window
touch /tmp/all_perm.txt && chmod 700 /tmp/all_perm.txt
echo "Initial: $(ls -l /tmp/all_perm.txt | awk '{print $1}')"
chmod a+r /tmp/all_perm.txt
echo "After a+r: $(ls -l /tmp/all_perm.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rwx------
After a+r: -rwxr--r--
  • a= without modification removes all permissions (be careful!)
  • a is default if no user specified (u+x is same as a+x? No, actually u+x means user only)
  • a+r adds read for user, group, and other
  • a-w removes write from all three categories

Batch permission changes for all users

a-w removes write from all users. a=r sets all users to read-only permission.

Code
Terminal window
# Add read for all users
chmod a+r file.txt
# Remove write from all
chmod a-w file.txt
# Make fully public readable/executable
chmod a+rx directory/
# Remove all permissions (make inaccessible)
chmod a= file.txt
# Set standard read-only
chmod a=r file.txt
# Set standard read and execute for all
chmod a=rx script.sh
# Remove execute from all (no one can run)
chmod a-x file.sh
Execution
Terminal window
touch /tmp/batch.txt && chmod 644 /tmp/batch.txt
echo "Initial: $(ls -l /tmp/batch.txt | awk '{print $1}')"
chmod a-w /tmp/batch.txt
echo "After a-w: $(ls -l /tmp/batch.txt | awk '{print $1}')"
chmod a=r /tmp/batch.txt
echo "After a=r: $(ls -l /tmp/batch.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rw-r--r--
After a-w: -r--r--r--
After a=r: -r--r--r--
  • a+r and a-w are quick ways to set permissions for everyone
  • a= is dangerous and rarely used
  • Prefer specific u/g/o for clarity
  • a is useful for quick batch changes

Operators

Understanding chmod operators for modifying permissions

Adding Permissions

Adding permissions with the + operator

Adding permissions with + operator

The + operator adds permissions incrementally. Each chmod command adds without removing existing permissions.

Code
Terminal window
# Add permissions with + operator
# Syntax: chmod [ugoa]+[rwxXst] file
# Examples:
chmod u+r file.txt # add read for user
chmod u+w file.txt # add write for user
chmod u+x file.txt # add execute for user
chmod g+r file.txt # add read for group
chmod o+x directory/ # add execute for other
chmod a+r file.txt # add read for all
# Multiple permissions at once:
chmod u+rwx file.txt # add read, write, execute for user
chmod g+rx file.txt # add read and execute for group
chmod a+x script.sh # add execute for all
Execution
Terminal window
touch /tmp/add_test.txt && chmod 000 /tmp/add_test.txt
echo "Initial: $(ls -l /tmp/add_test.txt | awk '{print $1}')"
chmod u+r /tmp/add_test.txt
echo "After u+r: $(ls -l /tmp/add_test.txt | awk '{print $1}')"
chmod u+w /tmp/add_test.txt
echo "After u+w: $(ls -l /tmp/add_test.txt | awk '{print $1}')"
Output
Terminal window
Initial: ----------
After u+r: -r--------
After u+w: -rw-------
  • + adds permissions without affecting other bits
  • Can add multiple at once (u+rwx)
  • Non-destructive - existing permissions retained
  • Ideal for incremental permission changes

Combining multiple additions in one command

Multiple additions with + can be combined with commas. User permissions unchanged, group and other now have read.

Code
Terminal window
# Add multiple permissions in one command
chmod u+rwx,g+rx,o+r file.txt
# Make executable by all without changing other bits
chmod a+x script.sh
# Add read and write for user and group
chmod u+rw,g+rw file.txt
# Add write for group and other
chmod g+w,o+w file.txt
# Add execute for user only
chmod u+x file.sh
# Add read for group and other
chmod g+r,o+r file.txt
Execution
Terminal window
touch /tmp/multi_add.txt && chmod 600 /tmp/multi_add.txt
echo "Initial: $(ls -l /tmp/multi_add.txt | awk '{print $1}')"
chmod g+r,o+r /tmp/multi_add.txt
echo "After g+r,o+r: $(ls -l /tmp/multi_add.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rw-------
After g+r,o+r: -rw-r--r--
  • Use commas to separate multiple operations
  • Each part is applied in sequence
  • Previous permissions are preserved
  • Efficient way to set complex permissions

Removing Permissions

Removing permissions with the - operator

Removing permissions with - operator

The - operator removes specific permissions. Files progress from 777 to 770 to 555.

Code
Terminal window
# Remove permissions with - operator
# Syntax: chmod [ugoa]-[rwxXst] file
# Examples:
chmod u-r file.txt # remove read from user
chmod u-w file.txt # remove write from user
chmod u-x file.txt # remove execute from user
chmod g-w file.txt # remove write from group
chmod o-r file.txt # remove read from other
chmod a-x script.sh # remove execute from all
# Multiple permissions at once:
chmod u-rwx file.txt # remove all from user
chmod g-rx file.txt # remove read and execute from group
chmod a-w file.txt # remove write from all
Execution
Terminal window
touch /tmp/rem_test.txt && chmod 777 /tmp/rem_test.txt
echo "Initial: $(ls -l /tmp/rem_test.txt | awk '{print $1}')"
chmod o-r /tmp/rem_test.txt
echo "After o-r: $(ls -l /tmp/rem_test.txt | awk '{print $1}')"
chmod a-w /tmp/rem_test.txt
echo "After a-w: $(ls -l /tmp/rem_test.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rwxrwxrwx
After o-r: -rwxrwx---
After a-w: -r-xr-x---
  • removes permissions without affecting other bits
  • Can remove multiple at once (u-rwx)
  • Non-destructive - other permissions retained
  • Ideal for revoking specific access

Revoking access and tightening security

Removing permissions progressively tightens access. File goes from 644 to 600 to 400.

Code
Terminal window
# Remove write permission from insecure files
chmod a-w file.txt
# Revoke group write access
chmod g-w file.txt
# Remove other's read access
chmod o-r file.txt
# Remove all permissions from other
chmod o-rwx file.txt
# Remove write for user and group
chmod u-w,g-w file.txt
# Revoke execute from script
chmod a-x script.sh
# Remove group and other access entirely
chmod go-rwx file.txt (same as chmod u=rwx file.txt)
Execution
Terminal window
touch /tmp/secure.txt && chmod 644 /tmp/secure.txt
echo "Initial: $(ls -l /tmp/secure.txt | awk '{print $1}')"
chmod g-r,o-r /tmp/secure.txt
echo "After g-r,o-r: $(ls -l /tmp/secure.txt | awk '{print $1}')"
chmod a-w /tmp/secure.txt
echo "After a-w: $(ls -l /tmp/secure.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rw-r--r--
After g-r,o-r: -rw-------
After a-w: -r--------
  • Useful for security hardening
  • Removes only specified permissions
  • Other permissions preserved
  • Good practice for preventing accidental modifications

Setting Exact Permissions

Setting permissions to exact state with = operator

Setting exact permissions with = operator

The = operator sets exact permissions for specified category. Unspecified categories retain existing permissions.

Code
Terminal window
# Set exact permissions with = operator
# Syntax: chmod [ugoa]=[rwxXst] file
# Note: = sets ONLY what you specify, removes everything else
# Examples:
chmod u=rwx file.txt # user has rwx, nothing else
chmod g=r file.txt # group has r, nothing else
chmod o= file.txt # other has nothing
chmod a=r file.txt # all have r only, no w or x
# Setting entire perms:
chmod u=rwx,g=rx,o=rx directory/ # sets 755
chmod u=rw,g=r,o=r file.txt # sets 644
chmod u=rwx,g=,o= file.txt # sets 700
Execution
Terminal window
touch /tmp/set_test.txt && chmod 777 /tmp/set_test.txt
echo "Initial: $(ls -l /tmp/set_test.txt | awk '{print $1}')"
chmod u=rw /tmp/set_test.txt
echo "After u=rw: $(ls -l /tmp/set_test.txt | awk '{print $1}')"
chmod g=r,o= /tmp/set_test.txt
echo "After g=r,o=: $(ls -l /tmp/set_test.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rwxrwxrwx
After u=rw: -rw-rwxrwx
After g=r,o=: -rw-r-----
  • = completely resets specified user/group/other
  • Unmodified categories keep their permissions
  • More destructive than + or -
  • Useful for setting standard modes

Setting standard permission modes

Setting u=rw,g=r,o=r creates standard 644 permissions. User gets read/write, group and other get read only.

Code
Terminal window
# Set standard 644 (file) permissions
chmod u=rw,g=r,o=r file.txt
# Set standard 755 (directory) permissions
chmod u=rwx,g=rx,o=rx directory/
# Set private 600 permissions
chmod u=rw,g=,o= private.key
# Set private directory 700
chmod u=rwx,g=,o= private_dir/
# Set collaborative 770
chmod u=rwx,g=rwx,o= shared.txt
# Set read-only for all
chmod u=r,g=r,o=r readonly.txt
# Set execute for all
chmod u=x,g=x,o=x execute.sh
Execution
Terminal window
touch /tmp/std_644.txt && chmod u=rw,g=r,o=r /tmp/std_644.txt && ls -l /tmp/std_644.txt | awk '{print $1}'
Output
Terminal window
-rw-r--r--
  • Useful for enforcing standard modes
  • More verbose than octal but clearer intent
  • Equivalent to octal chmod 644
  • Good for documentation and scripts

Multiple Changes

Combining multiple permission changes in one command

Chaining multiple permission changes

Multiple changes separated by commas are applied sequentially. One command sets user=rw, group=r, other nothing.

Code
Terminal window
# Combine multiple changes with commas
# Syntax: chmod change1,change2,change3 file
# Examples:
chmod u+rx,g+r,o-rw file.txt # add user rx, add group r, remove other rw
chmod u=rw,g=r,o=r file.txt # set user rw, group r, other r (644)
chmod a+r,a-w file.txt # add read for all, remove write from all
chmod u+x,g+x,o+x file.sh # make executable for all
# Complex multi-step changes:
chmod g-w,o-x file.txt # revoke group write and other execute
chmod u-rwx,g-rwx,o-rwx file.txt # remove all permissions
# Setting up standard modes in one go:
chmod u=rwx,g=rx,o=rx script.sh # set 755 for executable
chmod u=rw,g=,o= secrets.key # set 600 for private key
Execution
Terminal window
touch /tmp/multi_change.txt && chmod 777 /tmp/multi_change.txt
echo "Initial: $(ls -l /tmp/multi_change.txt | awk '{print $1}')"
chmod u=rw,g=r,o= /tmp/multi_change.txt
echo "After multi-change: $(ls -l /tmp/multi_change.txt | awk '{print $1}')"
Output
Terminal window
Initial: -rwxrwxrwx
After multi-change: -rw-r-----
  • Comma-separated changes applied left to right
  • No spaces allowed around commas
  • More efficient than multiple chmod commands
  • Useful in scripts for atomicity

Real-world permission setup scenarios

Multiple changes efficiently set up files with appropriate permissions for config (private), script (executable), and data (readable).

Code
Terminal window
# Setup web server script (700 but user only)
chmod u=rwx,g=,o= /etc/init.d/myserver
# Setup configuration file (owner only rw)
chmod u=rw,g=,o= /etc/myapp/config
# Setup log file (owner rw, group r)
chmod u=rw,g=r,o= /var/log/myapp.log
# Setup public html (all can read)
chmod u=rw,g=r,o=r /var/www/html/index.html
# Setup shared directory (team collaboration)
chmod u=rwx,g=rwx,o=rx /home/team/shared/
# Setup sensitive data (owner only)
chmod u=r,g=,o= ~/.ssh/id_rsa
# Setup executable script (owner rwx, group/other rx)
chmod u=rwx,g=rx,o=rx /usr/local/bin/myscript
Execution
Terminal window
mkdir -p /tmp/setup_demo && touch /tmp/setup_demo/{config,script,data}
chmod u=rw,g=,o= /tmp/setup_demo/config
chmod u=rwx,g=rx,o= /tmp/setup_demo/script
chmod u=rw,g=r,o=r /tmp/setup_demo/data
ls -l /tmp/setup_demo/
Output
Terminal window
total 0
-rw------- 1 user group 0 Feb 28 10:00 config
-rwxr-x--- 1 user group 0 Feb 28 10:00 script
-rw-r--r-- 1 user group 0 Feb 28 10:00 data
  • Combines multiple chmod operations into single command
  • More efficient than separate chmod calls
  • Atomicity helps in scripts and batch operations
  • Clear intention with multiple changes

Special Permissions

Understanding and using setuid, setgid, and sticky bit

Setuid Bit

Understanding and using the setuid special permission

Understanding setuid bit

The 's' in the user execute position indicates setuid is set. The file executes with owner's permissions.

Code
Terminal window
# Setuid (Set User ID) bit = 4000
# When set on executable file:
# - File executes with owner's permissions, not executor's
# - Only valid on executable files (not directories)
# - Shown as 's' in user execute position (rwsr-xr-x)
# In octal notation:
# First digit: 4 = setuid
# chmod 4755 = -rwsr-xr-x (setuid + rwxr-xr-x)
# chmod 4750 = -rwsr-x--- (setuid + rwxr-x---)
# Symbolic notation:
# chmod u+s file.sh # add setuid bit
# chmod u-s file.sh # remove setuid bit
# Use cases:
# - Password utilities (passwd, sudo)
# - System maintenance tools
# - Allows unprivileged users to temporarily gain elevated access
Execution
Terminal window
touch /tmp/suid_test.sh && chmod 755 /tmp/suid_test.sh && chmod u+s /tmp/suid_test.sh
ls -l /tmp/suid_test.sh
Output
Terminal window
-rwsr-xr-x 1 user group 0 Feb 28 10:00 /tmp/suid_test.sh
  • Setuid shown as 's' replacing 'x' if execute present, 'S' if not
  • Dangerous on frequently-used files
  • Never use setuid on shell scripts if possible
  • Binary (compiled) programs are safer with setuid

Setting and viewing setuid bits

Chmod 4755 sets setuid (4) plus standard executable permissions (755). The 's' indicates setuid presence.

Code
Terminal window
# Add setuid bit
chmod u+s /usr/bin/somecommand
chmod 4755 /usr/bin/somecommand
# Remove setuid bit
chmod u-s /usr/bin/somecommand
chmod 755 /usr/bin/somecommand
# Verify setuid is set
ls -l /usr/bin/somecommand # look for 's' in position 3
stat /usr/bin/somecommand
# View files with setuid set
find /usr/bin -perm -4000
# View as 4-digit octal
stat -c "%a %A %n" /usr/bin/somecommand
Execution
Terminal window
touch /tmp/su_demo && chmod 4755 /tmp/su_demo && ls -l /tmp/su_demo && stat -c "%a %A" /tmp/su_demo
Output
Terminal window
-rwsr-xr-x 1 user group 0 Feb 28 10:00 /tmp/su_demo
4755 -rwsr-xr-x
  • 4755 = setuid(4) + rwxr-xr-x(755)
  • Octal notation clearly shows setuid with leading 4
  • ls shows 's' in user execute position
  • stat shows full 4-digit octal including special bits

Setgid Bit

Understanding and using the setgid special permission

Understanding setgid bit

The 's' in the group execute position indicates setgid is set on the directory. Files created inherit group ownership.

Code
Terminal window
# Setgid (Set Group ID) bit = 2000
# When set on executable file:
# - File executes with owner's group permissions
# When set on directory:
# - New files created inherit directory's group, not creator's
# - Enables collaborative directories
# - Shown as 's' in group execute position (rwxr-sr-x)
# In octal notation:
# First digit: 2 = setgid
# chmod 2755 = -rwxr-sr-x (setgid + rwxr-xr-x)
# chmod 2770 = -rwxrws--- (setgid + rwxrwx---)
# Symbolic notation:
# chmod g+s directory/ # add setgid on directory
# chmod g+s file.sh # add setgid on file
# Use cases:
# - Collaborative directories (inherit group ownership)
# - Shared project folders
# - Group-based permissions
Execution
Terminal window
mkdir -p /tmp/setgid_test && chmod 2755 /tmp/setgid_test && ls -ld /tmp/setgid_test
Output
Terminal window
drwxr-sr-x 2 user group 4096 Feb 28 10:00 /tmp/setgid_test
  • Setgid on directory: new files inherit directory's group
  • Setgid on file: executes with owner's group
  • Shown as 's' in group execute position
  • Very useful for collaborative directories

Using setgid for collaborative directories

Chmod 2770 sets setgid (2) plus rwxrwx--- (770). Files created inherit directory's group.

Code
Terminal window
# Create group-shared directory with setgid
mkdir /home/team/shared
chmod g+w /home/team/shared
chmod g+s /home/team/shared
# Verify new files inherit group
touch /home/team/shared/newfile.txt
ls -l /home/team/shared/newfile.txt
# File will have group ownership of 'team' instead of user's primary group
# Set permissions for collaborative work
chmod 2770 /home/team/shared
# Files created match directory group
chmod g+s directory/ # symbolic method
chmod 2755 directory/ # octal equivalent for rwxr-sr-x
Execution
Terminal window
mkdir -p /tmp/collab && chmod 2770 /tmp/collab && ls -ld /tmp/collab
Output
Terminal window
drwxrws--- 2 user group 4096 Feb 28 10:00 /tmp/collab
  • 2770 = setgid(2) + rwxrwx---(770)
  • Enables group-based collaboration
  • New files automatically group-owned
  • Essential for team projects

Sticky Bit

Understanding and using the sticky bit special permission

Understanding sticky bit

The 't' in the other execute position indicates sticky bit is set. Only file owners can delete their files.

Code
Terminal window
# Sticky bit = 1000
# When set on directory:
# - Only owner (or root) can delete own files
# - Prevents users from deleting others' files
# - Shown as 't' in other execute position (rwxrwxrwt)
# - NOT valid on regular files (ignored)
# In octal notation:
# First digit: 1 = sticky
# chmod 1777 = rwxrwxrwt (sticky + rwxrwxrwx)
# chmod 1755 = rwxr-xr-t (sticky + rwxr-xr-x)
# Symbolic notation:
# chmod o+t directory/ # add sticky bit on directory
# chmod o-t directory/ # remove sticky bit
# Use cases:
# - /tmp and /var/tmp (prevent users deleting others' files)
# - Shared directories needing file protection
# - Collaborative spaces where only owners delete own files
Execution
Terminal window
mkdir -p /tmp/sticky_test && chmod 1777 /tmp/sticky_test && ls -ld /tmp/sticky_test
Output
Terminal window
drwxrwxrwt 2 user group 4096 Feb 28 10:00 /tmp/sticky_test
  • Sticky bit shown as 't' in other execute position
  • Lowercase 't' if execute present, uppercase 'T' if not
  • Typically combined with 777 on shared directories
  • Essential for shared temp directories

Setting and verifying sticky bit

First directory (777) shows 'x' in other; second (1777) shows 't'. Only in second can non-owners not delete others' files.

Code
Terminal window
# Set sticky bit on shared directory
chmod o+t /tmp/shared
chmod 1777 /tmp/shared
# Verify sticky is set
ls -ld /tmp/shared # look for 't' in position 10
stat /tmp/shared
# View as 4-digit octal
stat -c "%a %A %n" /tmp/shared
# Remove sticky bit
chmod o-t /tmp/shared
# Find directories with sticky bit
find /tmp -perm -1000 -type d
# Compare: with and without sticky
chmod 777 /tmp/test1 # 0777
chmod 1777 /tmp/test2 # 1777 (sticky)
ls -ld /tmp/test1 /tmp/test2
Execution
Terminal window
mkdir -p /tmp/sticky1 /tmp/sticky2 && chmod 777 /tmp/sticky1 && chmod 1777 /tmp/sticky2
ls -ld /tmp/sticky1 /tmp/sticky2
Output
Terminal window
drwxrwxrwx 2 user group 4096 Feb 28 10:00 /tmp/sticky1
drwxrwxrwt 2 user group 4096 Feb 28 10:00 /tmp/sticky2
  • 1777 = sticky(1) + rwxrwxrwx(777)
  • 't' indicates sticky bit protection
  • Standard for /tmp directories
  • Prevents accidental file deletion

Recursive Operations

Applying chmod recursively to directories and contents

Recursive Changes

Using -R flag for recursive permission changes

Basic recursive permission changes

chmod -R 644 applies 644 permissions to all files in the directory tree. All files show -rw-r--r--.

Code
Terminal window
# Recursive chmod with -R flag
# Syntax: chmod -R mode directory
# Apply permissions to all contents of directory
chmod -R 755 /path/to/directory
# Make all files executable recursively
chmod -R u+x /path/to/directory
# Remove write from all files recursively
chmod -R a-w /path/to/directory
# Set permissions for all subdirectories
chmod -R 700 /path/to/private/
# Recursive examples:
chmod -R 644 ./myproject/ # all files 644
chmod -R u+r ./myproject/ # add read for all
chmod -R o-rwx ./myproject/ # remove other access
Execution
Terminal window
mkdir -p /tmp/recursivetest/{dir1,dir2} && touch /tmp/recursivetest/{file1.txt,dir1/file2.txt,dir2/file3.txt}
chmod -R 644 /tmp/recursivetest && find /tmp/recursivetest -type f -exec ls -l {} \; | awk '{print $1}'
Output
Terminal window
-rw-r--r--
-rw-r--r--
-rw-r--r--
  • -R recursively applies to all contents
  • Applied to files AND directories
  • May result in inaccessible directories (need x for traversal)
  • Use with caution on important directories

Recursive permission setup for projects

Using find with type filter correctly sets files to 644 and directories to 755 separately.

Code
Terminal window
# Setup project directory structure
# Directories need rwx for access
# Files typically 644, directories 755
# Make all files readable
chmod -R u+r,g+r,o+r ./project/
# Make all files non-writable except owner
chmod -R u-w,g-w,o-w ./project/
chmod -R u+w ./project/
# Make all directories executable
find ./project/ -type d -exec chmod 755 {} \;
# Alternative: single recursive that might lock you out
chmod -R 644 ./project/ # DANGER: directories become inaccessible!
# Better approach: handle files and directories separately
find ./project/ -type f -exec chmod 644 {} \;
find ./project/ -type d -exec chmod 755 {} \;
Execution
Terminal window
mkdir -p /tmp/proj/{src,docs} && touch /tmp/proj/{README.md,src/main.py,docs/guide.md}
find /tmp/proj -type f -exec chmod 644 {} \;
find /tmp/proj -type d -exec chmod 755 {} \;
find /tmp/proj -type f -o -type d | xargs ls -ld | awk '{print $1, $NF}'
Output
Terminal window
-rw-r--r-- /tmp/proj/README.md
-rw-r--r-- /tmp/proj/src/main.py
-rw-r--r-- /tmp/proj/docs/guide.md
drwxr-xr-x /tmp/proj
drwxr-xr-x /tmp/proj/src
drwxr-xr-x /tmp/proj/docs
  • -R applies to everything; often too broad
  • Use find to differentiate files and directories
  • Files typically 644, directories 755
  • Prevents locking yourself out of directories

Recursive with Options

Combining recursive with verbose and other options

Verbose recursive operations

Chmod -Rc shows only items that were actually changed. With -v, all items would be listed.

Code
Terminal window
# -R: Recursive (required)
# -v: Verbose (show all changes)
# -c: Changes only (show only changed items)
# -f: Force/quiet (suppress errors)
# Common combinations:
# chmod -R -v 755 dir/ # recursive + verbose
# chmod -Rv 755 dir/ # combined flags (same as above)
# chmod -Rc 755 dir/ # recursive + changes only
# Examples:
chmod -Rv 644 ./myfiles/ # show all changes
chmod -Rc 755 ./project/ # show only what changed
chmod -Rf 755 ./dir/ # force, suppress errors
chmod -Rvc 644 ./src/ | head -20 # verbose + limit output
Execution
Terminal window
mkdir -p /tmp/verb_test && touch /tmp/verb_test/{f1.txt,f2.txt,f3.txt}
chmod -Rc 644 /tmp/verb_test 2>&1 | head -5
Output
Terminal window
mode of '/tmp/verb_test/f1.txt' changed from 0644 to 0644
  • -Rv shows all files processed
  • -Rc shows only files that had permission changes
  • -Rf suppresses error messages
  • Useful for scripts and large operations

Tracking recursive changes with verbose and logging

-Rc lists only items with actual permission changes. Output can be captured for audit trails.

Code
Terminal window
# Log all changes made
chmod -Rv 755 /path/to/dir > chmod_log.txt 2>&1
# Count changes made
chmod -Rc 644 /path/to/dir | wc -l
# Show changes with timestamps
date && chmod -Rc 755 /path/to/dir && date
# Audit changes after recursive chmod
chmod -Rc 700 /path/ > changes.log
cat changes.log | head -20
cat changes.log | tail -5
# Compare sizes before and after
du -sh /path/before && chmod -R 755 /path/ && du -sh /path/after
Execution
Terminal window
mkdir -p /tmp/log_test && touch /tmp/log_test/{a,b,c}.txt
chmod -Rc 755 /tmp/log_test 2>&1 | head -3
Output
Terminal window
mode of '/tmp/log_test/a.txt' changed from 0644 to 0755
mode of '/tmp/log_test/b.txt' changed from 0644 to 0755
mode of '/tmp/log_test/c.txt' changed from 0644 to 0755
  • -Rc useful for audit logging
  • Can redirect output to file for documentation
  • Combine with wc -l to count changes
  • Good for tracking configuration changes

Advanced Usage

Advanced chmod techniques and options

Reference Mode

Using --reference flag to copy permissions from another file

Copy permissions from reference file

chmod --reference copies exact permissions from template to target file without specifying numeric mode.

Code
Terminal window
# Copy permissions from one file to another
# Syntax: chmod --reference=source_file target_file
# Examples:
chmod --reference=/etc/passwd /tmp/myconf
chmod --reference=template.txt *.txt
# Use cases:
# - Match file permissions to template
# - Standardize permissions across files
# - Copy permissions without knowing exact mode
# Combined with find:
find . -name "*.log" -exec chmod --reference=template.log {} \;
# Verify same permissions
stat -c "%a %A" template.txt
stat -c "%a %A" newfile.txt
Execution
Terminal window
touch /tmp/template && touch /tmp/testfile && chmod 650 /tmp/template
chmod --reference=/tmp/template /tmp/testfile
echo "Template: $(ls -l /tmp/template | awk '{print $1}')"
echo "File: $(ls -l /tmp/testfile | awk '{print $1}')"
Output
Terminal window
Template: -rw-r-x---
File: -rw-r-x---
  • Useful for matching permissions across files
  • No need to know exact permissions of reference
  • Template file must exist and be accessible
  • Works with any file permissions

Batch applying template permissions with reference

Using chmod --reference in a loop applies template permissions to multiple files efficiently.

Code
Terminal window
# Create template file with desired permissions
touch standard_template
chmod 644 standard_template
# Apply to all files in directory
for file in *.txt; do
chmod --reference=standard_template "$file"
done
# Using find to apply template
find . -type f -name "*.log" -exec chmod --reference=/etc/syslog.conf {} \;
# Verify all have same permissions
find . -type f -exec ls -l {} \; | awk '{print $1}' | sort | uniq
Execution
Terminal window
mkdir -p /tmp/batch_ref && touch /tmp/batch_ref/template /tmp/batch_ref/{f1,f2,f3}.txt
chmod 700 /tmp/batch_ref/template
for f in /tmp/batch_ref/*.txt; do chmod --reference=/tmp/batch_ref/template "$f"; done
ls -l /tmp/batch_ref/*.txt | awk '{print $1}'
Output
Terminal window
-rwx------
-rwx------
-rwx------
  • Useful for batch operations
  • Template-based consistency
  • Works with find and loops
  • No need to calculate modes manually

Logical Operators

Understanding logical operators in permission expressions

Combining permissions with logical operators

Multiple changes with commas are applied sequentially. Result is rw-r----- (640 permissions).

Code
Terminal window
# Comma-separated list of changes all applied
# chmod u+rwx,g+rx,o-rwx file
# All changes are processed in sequence
# Each builds on previous result
# Examples:
chmod u+rw,g+r,o=r file.txt # set specific perms
chmod a+r,u+w file.txt # add read all, add write user
chmod u-w,g-w,o-w file.txt # remove write from all
chmod u=rwx,g=rx,o= directory/ # set 750 permissions
# Order matters for clarity, usually:
# 1. User changes
# 2. Group changes
# 3. Other changes
Execution
Terminal window
touch /tmp/logic_test && chmod 000 /tmp/logic_test
chmod u+rw,g+r,o= /tmp/logic_test && ls -l /tmp/logic_test | awk '{print $1}'
Output
Terminal window
-rw-r-----
  • Comma separates multiple changes
  • No spaces around comma
  • Changes applied left to right
  • Each change builds on previous result

Complex permission expressions

Complex expression sets user with setuid+rwx, group read, other nothing. Resulting in 4540.

Code
Terminal window
# Build complex permissions in single command
chmod u=rwx,g=rx,o= script.sh # 750: user full, group rx, other none
# Add and remove in same command
chmod a+r,a-x file.txt # add read all, remove execute all
# Different operations for different users
chmod u+w,g-w,o-rwx file.txt # user add write, group rem write, other none
# Combining with special bits
chmod u+rws,g+rx,o= program.sh # setuid + rwx for user, rx for group
# Security hardening in one command
chmod u-x,g-rwx,o-rwx file.txt # remove execute user, all from group/other
Execution
Terminal window
touch /tmp/complex && chmod 777 /tmp/complex
chmod u+rws,g+r,o= /tmp/complex && ls -l /tmp/complex | awk '{print $1}'
Output
Terminal window
-rwsr-----
  • Multiple operations enable complex setups
  • Setuid/setgid/sticky in complex expressions
  • Single command atomic operation
  • More readable than octal for complex requirements

Batch Operations

Performing chmod on multiple files efficiently

Batch chmod using find and xargs

find selects only *.txt files and chmod applies 600 to them. c.py remains unchanged.

Code
Terminal window
# Using find to locate and chmod files
find /path -type f -exec chmod 644 {} \;
# Using find with xargs (more efficient)
find /path -type f -print0 | xargs -0 chmod 644
# Separate files and directories
find /path -type f -exec chmod 644 {} \;
find /path -type d -exec chmod 755 {} \;
# Limited depth search
find /path -maxdepth 2 -type f -exec chmod 644 {} \;
# Specific file patterns
find /path -name "*.txt" -exec chmod 644 {} \;
find /path -name "*.sh" -exec chmod 755 {} \;
Execution
Terminal window
mkdir -p /tmp/batch && touch /tmp/batch/{a.txt,b.txt,c.py}
find /tmp/batch -name "*.txt" -exec chmod 600 {} \;
ls -l /tmp/batch | awk '{print $1, $NF}'
Output
Terminal window
total 0
-rw------- a.txt
-rw------- b.txt
-rw-r--r-- c.py
  • find is precise for selecting files
  • -exec runs chmod on each found file
  • xargs is more efficient for large lists
  • maxdepth prevents deep recursion if desired

Advanced batch operations with patterns

Different file types get different permissions using separate find commands with name patterns.

Code
Terminal window
# Apply different permissions based on file types
find . -type f -name "*.sh" -exec chmod 755 {} \;
find . -type f -name "*.py" -exec chmod 755 {} \;
find . -type f -name "*.conf" -exec chmod 640 {} \;
# Batch operations with conditions
find . -type f -size +1M -exec chmod 444 {} \; # large files read-only
# Complex find with chmod
find . -perm 777 -exec chmod 755 {} \; # change overly permissive
# Using -newer for recent files
find . -type f -newer lastmod -exec chmod 644 {} \;
# Batch with progress reporting
find . -type f | wc -l # count first
find . -type f -print0 | xargs -0 chmod 644
Execution
Terminal window
mkdir -p /tmp/advanced_batch && touch /tmp/advanced_batch/{script.sh,config.conf,data.txt}
chmod 777 /tmp/advanced_batch/*
find /tmp/advanced_batch -name "*.sh" -exec chmod 755 {} \;
find /tmp/advanced_batch -name "*.conf" -exec chmod 640 {} \;
ls -l /tmp/advanced_batch | awk '{print $1, $NF}'
Output
Terminal window
total 0
-rw-r----- config.conf
-rw-r--r-- data.txt
-rwxr-xr-x script.sh
  • Chaining find commands handles different file types
  • Efficient for maintaining consistent permissions
  • Can add conditions for selective application
  • Scripts/binaries get 755, configs 640, data 644

Practical Examples

Real-world chmod scenarios and practical use cases

Real-World Scenarios

Common practical chmod use cases

Securing SSH key files

SSH keys require specific permissions: directory 700, private key 600, public key 644. Essential for SSH security.

Code
Terminal window
# SSH keys must be private and non-world-readable
chmod 600 ~/.ssh/id_rsa # private key readable only by owner
chmod 644 ~/.ssh/id_rsa.pub # public key can be read by anyone
chmod 700 ~/.ssh/ # SSH directory owner only
# Set correct permissions on new SSH directory
mkdir ~/.ssh
chmod 700 ~/.ssh
# Keys from others must be protected
chmod 600 ~/.ssh/authorized_keys # control access to account
# Fix common SSH permission issues
chmod 755 ~/ # home directory accessible
chmod 700 ~/.ssh # SSH directory private
chmod 600 ~/.ssh/id_rsa # private key secure
Execution
Terminal window
mkdir -p /tmp/ssh_test/.ssh && touch /tmp/ssh_test/.ssh/{id_rsa,id_rsa.pub}
chmod 700 /tmp/ssh_test/.ssh && chmod 600 /tmp/ssh_test/.ssh/id_rsa && chmod 644 /tmp/ssh_test/.ssh/id_rsa.pub
ls -la /tmp/ssh_test/.ssh/
Output
Terminal window
total 8
drwx------ 2 user group 4096 Feb 28 10:00 .
dr-xr-xr-x 3 user group 4096 Feb 28 10:00 ..
-rw------- 1 user group 0 Feb 28 10:00 id_rsa
-rw-r--r-- 1 user group 0 Feb 28 10:00 id_rsa.pub
  • SSH refuses if .ssh is not 700
  • Private keys must be 600
  • Public keys can be 644
  • Home directory typically 755
  • Critical for security

Web server file permissions

Web files typically use 644 (readable by all, writable by owner) with 755 directories for traversal.

Code
Terminal window
# Web server files and directories
# htdocs/html files readable by everyone, writable only by owner
chmod 644 /var/www/html/*.html # HTML files
chmod 644 /var/www/html/*.css # CSS files
chmod 644 /var/www/html/*.js # JavaScript
chmod 755 /var/www/html/ # directory must be traversable
# Server-side scripts (PHP, Python, etc.)
chmod 644 /var/www/html/*.php # script file readable by server
chmod 644 /var/www/cgi-bin/* # CGI scripts
# Upload directories (writable by server)
chmod 755 /var/www/html/uploads/ # directory writable
chmod 755 /var/www/html/tmp/ # temp directory
# Configuration files (private)
chmod 600 /var/www/html/config.php # config secure
chmod 600 /var/www/html/.env # environment file
Execution
Terminal window
mkdir -p /tmp/webroot && touch /tmp/webroot/{index.html,style.css,config.php}
chmod 755 /tmp/webroot && chmod 644 /tmp/webroot/{index.html,style.css} && chmod 600 /tmp/webroot/config.php
ls -la /tmp/webroot/ | tail -+4 | awk '{print $1, $NF}'
Output
Terminal window
-rw-r--r-- config.php
-rw-r--r-- index.html
-rw-r--r-- style.css
  • HTML/CSS/JS files: 644
  • Directories: 755
  • Config files: 600
  • Owner must be restorable (usually root or app user)

Configuration and system files

Configuration files (644), executables (755), and logs (640-650) have different permission requirements.

Code
Terminal window
# System configuration files
chmod 644 /etc/passwd # readable by all, root write
chmod 640 /etc/shadow # readable by root/group only
chmod 644 /etc/hosts # readable by all
chmod 644 /etc/hostname # readable by all
# System scripts and binaries
chmod 755 /usr/local/bin/myscript # executable by all
chmod 755 /etc/init.d/myservice # service script executable
# Log files
chmod 640 /var/log/myapp.log # readable by owner/group
chmod 755 /var/log/ # directory traversable
# Application data files
chmod 640 /var/lib/myapp/database.db # readable by app
chmod 750 /var/lib/myapp/ # directory for group access
Execution
Terminal window
mkdir -p /tmp/sysconfig && touch /tmp/sysconfig/{config.ini,script.sh,app.log}
chmod 644 /tmp/sysconfig/config.ini && chmod 755 /tmp/sysconfig/script.sh && chmod 640 /tmp/sysconfig/app.log
ls -l /tmp/sysconfig | tail -+4 | awk '{print $1, $NF}'
Output
Terminal window
-rw-r----- app.log
-rw-r--r-- config.ini
-rwxr-xr-x script.sh
  • Config files typically 644 or 640
  • Scripts/binaries 755
  • Log files 640-650
  • Sensitive files 600

Security Best Practices

Security implications and best practices for file permissions

Principle of least privilege

Secure permissions (600) restrict to owner only. Insecure (666) allows anyone to modify the file.

Code
Terminal window
# Use minimum permissions necessary
# Start restrictive, add permissions as needed
# Private files: start with 600
chmod 600 sensitive.txt # only owner can read/write
# Read-only files: use 444
chmod 444 readonly.conf # no one can modify
# Executable only by owner: use 700
chmod 700 admin-only.sh # only owner can execute
# Shared group files: use 640 not 644
chmod 640 shared.log # group can read, others cannot
# Public files: use 644 minimum
chmod 644 public.html # all can read, none can write
# Never use 777 or 666
# Avoid: chmod 777 file.txt # INSECURE: all can do everything
# Avoid: chmod 666 file.txt # INSECURE: all can modify
# Audit tool:
# Find overly permissive files
find / -perm -002 -type f # world-writable
find / -perm -020 -type f # group-writable
Execution
Terminal window
touch /tmp/sec_test && chmod 600 /tmp/sec_test
echo "=== Secure (600) ===" && ls -l /tmp/sec_test
chmod 666 /tmp/sec_test 2>/dev/null || true
echo "=== Insecure (666) ===" && ls -l /tmp/sec_test
Output
Terminal window
=== Secure (600) ===
-rw------- 1 user group 0 Feb 28 10:00 /tmp/sec_test
=== Insecure (666) ===
-rw-rw-rw- 1 user group 0 Feb 28 10:00 /tmp/sec_test
  • 600 is secure, 644 for public reading
  • 666 is dangerous for any file
  • 777 very rarely justified
  • Audit regularly for over-permissive files

Preventing common security mistakes

Security improves from 644 (world-readable) to 600 (owner-only). Sensitive data must be 600.

Code
Terminal window
# WRONG: Making config world-readable
# chmod 644 /etc/myapp/db.conf # database password exposed!
# RIGHT: Keep config private
chmod 600 /etc/myapp/db.conf # only application can read
# WRONG: Making .ssh directory accessible
# chmod 755 ~/.ssh # allows SSH hijacking!
# RIGHT: Keep SSH directory private
chmod 700 ~/.ssh # only owner can access
# WRONG: Making shell scripts world-writable
# chmod 777 /usr/local/bin/script # anyone can modify!
# RIGHT: Script executable but not modifiable
chmod 755 /usr/local/bin/script # all can execute, owner writes
# WRONG: Making sensitive data world-readable
# chmod 644 ~/.aws/credentials # exposes AWS access!
# RIGHT: Keep credentials private
chmod 600 ~/.aws/credentials # only owner can read
# Audit for problems:
find ~ -perm -0077 # files with group/other access
find ~ -type f -perm /022 # group/other writable
Execution
Terminal window
touch /tmp/mistake && chmod 666 /tmp/mistake 2>&1 | head -1 || chmod 644 /tmp/mistake
echo "Insecure: $(ls -l /tmp/mistake | awk '{print $1}')"
chmod 600 /tmp/mistake
echo "Secure: $(ls -l /tmp/mistake | awk '{print $1}')"
Output
Terminal window
Insecure: -rw-r--r--
Secure: -rw-------
  • Database configs: 600
  • SSH directories: 700, keys: 600
  • Credentials: 600
  • Regular audit prevents exposure