Skip to content

Navigation & File Permissions

Before you can run any tool, you have to be able to move around a Linux filesystem with confidence and read (and set) who is allowed to do what to a given file. Get either wrong and the failure looks identical from the outside — "command not found" or "permission denied" — but the fix is completely different depending on which one it actually is.

TL;DR — in 30 seconds:

  • A path is either absolute (starts at /, always unambiguous) or relative (starts from your current directory, pwd) — know which one you're typing.
  • Every file has three permission classes (owner / group / others) and three permission bits each (read / write / execute) — rwxr-xr-- reads left to right, one triplet per class.
  • chmod accepts the same permissions as either symbolic (u+x) or octal (755) notation — they express the exact same bits, just spelled differently.

1. Moving around — absolute vs. relative paths

Every command that takes a path takes either an absolute path (starts with /, unambiguous no matter where you are) or a relative path (interpreted from your current working directory, shown by pwd).

flowchart LR
    A["A path"] --> B{"Starts with /?"}
    B -->|yes| C["Absolute<br/>/home/user/app — always the same file"]
    B -->|no| D["Relative<br/>app/config — depends on pwd"]
  • pwd — print the current working directory (where relative paths are anchored).
  • cd <path> — change directory; cd alone (no argument) returns you to your home directory; cd - returns to the previous directory.
  • ls, ls -l (long format: permissions, owner, group, size, modified time), ls -a (include dotfiles, the hidden files whose name starts with .).
  • Two relative shorthands appear in almost every path expression: . (the current directory) and .. (the parent directory) — cd ../.. moves up two levels.
  • ~ expands to your home directory — cd ~/projects and cd /home/you/projects are the same command.

2. Reading permissions

ls -l shows a ten-character string like -rwxr-xr-- for every entry. The first character is the file type (- regular file, d directory, l symlink); the remaining nine characters split into three groups of three:

Position Class Meaning
2–4 Owner (u) what the file's owning user can do
5–7 Group (g) what members of the owning group can do
8–10 Others (o) what everyone else can do

Within each triplet, the three bits are always in the same order: read, write, execute — a - in a position means that permission is absent.

Symbol On a file On a directory
r read the file's contents list the directory's contents
w modify the file's contents create/delete/rename entries inside it
x execute the file as a program/script cd into it, or access files by exact name inside it

So rwxr-xr-- reads: the owner can read/write/execute; the group can read/execute but not write; everyone else can only read.

3. Changing permissions — chmod

chmod takes the same permission change in either of two notations:

  • Symbolicchmod u+x script.sh (add execute for the owner), chmod go-w file (remove write from group and others), chmod a+r file (add read for all — a = owner+group+others).
  • Octal — each triplet collapses to one digit: r=4, w=2, x=1, summed. chmod 755 script.sh sets owner=rwx (4+2+1=7), group=r-x (4+0+1=5), others=r-x (5) — a very common "runnable by me, readable by everyone else" pattern.
Octal digit Bits Meaning
7 rwx read + write + execute
6 rw- read + write
5 r-x read + execute
4 r-- read only
0 --- nothing

chmod -R <mode> <dir> applies recursively to every file and subdirectory — powerful, and correspondingly easy to misuse (see the gotchas below).

4. Ownership — chown / chgrp

Permissions are checked against an owner and a group, so changing who owns a file changes whose u/ g bits apply to it:

  • chown <user> <file> — change the owning user.
  • chown <user>:<group> <file> — change owner and group in one call.
  • chgrp <group> <file> — change only the owning group.

Changing ownership itself normally requires elevated privileges (sudo) — you can't hand a file away to another user as an unprivileged owner.

5. How this connects

  • This course's next page, 02-text-processing-and-pipes.md — the file-reading permissions this page teaches (do you have r on the file you're about to grep?) are a prerequisite for every pipeline that page builds; a cat: Permission denied mid-pipe is this page's rwx model showing up one page later.
  • Containers (module 03, Containers, the rootless model and its USER-directive gotcha) — Podman's rootless containers map straight onto the owner/group model taught here: forgetting USER in a Containerfile means the process inside runs as root by default, the same "which owner actually applies" question §4's chown/chgrp answers for a file on disk.
  • Linux (RHEL) (module 09, Linux (RHEL), SELinux) — this page's "permission denied" gotcha only covers the Unix rwx model; RHEL layers a second, independent permission system (SELinux) on top, where a process can have fully correct Unix bits and still get denied — the two are easy to conflate but diagnosed completely differently.

Common gotchas

  • Reaching for chmod 777 to "just make it work." Fix: 777 grants write to everyone, not just execute to the owner — diagnose which of the nine bits is actually missing (usually just x for the owner) and set only that one.
  • Running chmod -R on a directory tree without checking what's inside first. Fix: a recursive chmod applies the exact same mode to files AND directories alike, which is often wrong — a directory typically needs x (to be enterable) even where a file inside it shouldn't have it; check the tree (or use find with -type f/-type d to target each separately) before running it wide.
  • Confusing "permission denied" with "command not found." Fix: "permission denied" means the shell found the file but you lack the required bit (usually execute, or you're not the owner); "command not found" means the shell never located the file at all — a $PATH problem, not a permissions one.
  • Assuming a relative path means the same thing in every terminal tab. Fix: relative paths are resolved against pwd, which is per-shell-session state — run pwd before trusting a relative path you're about to act on.
Check yourself — a file shows rw-r--r--. Can the owner execute it? Can the group write to it?

No to both. The owner's triplet (rw-) has no x, so the owner cannot execute it; the group's triplet (r--) has no w, so the group cannot write to it. Only the owner can read and write; everyone (owner, group, others) can read.

Check yourself — what octal number is rwxr-x---, and in plain words, who can do what?

750. Owner = rwx (7, full access), group = r-x (5, read + execute but not write), others = --- (0, no access at all).

You can defend this when you can read any ls -l permission string cold, convert it to (and from) its octal form, and explain which single bit is missing when a command fails with "permission denied."