One directory tree

A Linux system has a single directory tree. It starts at the root directory, written as /, and every file, every disk and every Universal Serial Bus (USB) stick is somewhere below it. The same character separates the levels of a path: /home/ana/projects is the directory projects, inside ana, inside home, inside /.

The layout of that tree follows the Filesystem Hierarchy Standard (FHS), which says which directory holds what, so that you find the same places on Ubuntu, Debian, Fedora and Red Hat Enterprise Linux (RHEL). The table of the main directories is in Linux at a Glance. For moving around, these are the ones you visit most:

Directory Why you go there
/home/user Your own files and personal settings
/etc To read or change the configuration of a service
/var/log To read log files when something goes wrong
/tmp Scratch space; anyone can write there, and it may be emptied at every restart
/usr/bin, /usr/sbin Where the programs are; sbin holds tools for administrators
/opt Add-on software from vendors, each in its own directory
/mnt, /media Where extra disks and removable media appear
/root The home directory of the root user (closed to ordinary users)

On current distributions /bin, /sbin and /lib are only links to their counterparts in /usr (the "merged /usr"), so /bin/ls and /usr/bin/ls are the same file. Older documentation that distinguishes them still works.

Part of a Linux directory tree. The root directory / contains etc, home, tmp, usr and var. home contains ana and ben; ana contains projects and notes.txt; var contains log. The path from / through home and ana to projects is highlighted. / etc home tmp usr var ana ben log projects notes.txt absolute: /home/ana/projects from /var/log: ../../home/ana/projects
One tree from /. The highlighted directory has one absolute path, and a different relative path from every other place in the tree.

Where am I? The working directory

Every shell (and every program) has a working directory, also called the current directory: the directory it is "in", where names without a path are looked up and new files are created by default. pwd (print working directory) shows it, and the default prompt shows it too.

$ pwd
/home/ana

When a command says "No such file or directory" for a file you are sure exists, the first thing to check is the working directory.

The home directory and ~

Your home directory is the directory that belongs to your account: it holds your files and your personal settings, and a new shell starts there. For ordinary users it is /home/name; for root it is /root. The shell offers three ways to write it:

  • ~ (tilde) on its own or at the start of a path: ~/projects is /home/ana/projects for Ana.
  • ~ben: the home directory of user ben.
  • $HOME: the variable that holds the path, the form to use in scripts.

The shell replaces ~ before the command runs, and only where it is not quoted: "~/projects" in quotes means a directory literally named ~ inside the working directory. Use "$HOME/projects" when you need quotes.

Absolute and relative paths

A path names a file or directory, and there are two kinds:

  • An absolute path starts with / and describes the way from the root: /var/log/syslog. It means the same thing no matter where you are, which makes it the right choice in scripts, configuration files and instructions for colleagues.
  • A relative path does not start with / and is read from the working directory: if you are in /var, log/syslog means /var/log/syslog. It is shorter to type, but its meaning changes when you move.

Two special names exist in every directory: . is the directory itself and .. is its parent (one level up). ../../home goes two levels up, then into home. In /, .. is simply / again.

The examples on this page start in an empty folder that serves as the home directory. They build a small tree first, and use sed to show the home directory as ~ in the output of pwd, the way the prompt does.

mkdir -p projects/website/css projects/notes

cd projects/website/css          # relative: from where we are
pwd | sed "s|$HOME|~|"
cd ../../notes                   # up two levels, then down into notes
pwd | sed "s|$HOME|~|"
cd ~/projects/website            # from the home directory
pwd | sed "s|$HOME|~|"
cd ./css/../../notes             # . and .. can appear anywhere
pwd | sed "s|$HOME|~|"
~/projects/website/css
~/projects/notes
~/projects/website
~/projects/notes

mkdir -p creates a directory together with any missing parent directories (see Working with Files and Directories).

Moving around with cd

Command Goes to
cd /var/log An absolute path
cd log A relative path, below the working directory
cd .. One level up
cd or cd ~ Your home directory
cd - The previous directory (and prints its name), handy for switching back and forth
mkdir -p projects/website/css projects/notes

cd projects/website
pwd | sed "s|$HOME|~|"
cd css
cd ..
pwd | sed "s|$HOME|~|"
cd ../notes
pwd | sed "s|$HOME|~|"
cd "$OLDPWD"                     # back to where we were
pwd | sed "s|$HOME|~|"
cd                               # home
pwd | sed "s|$HOME|~|"
~/projects/website
~/projects/website
~/projects/notes
~/projects/website
~

The variable OLDPWD holds the previous directory, and cd "$OLDPWD" is what cd - does. At the prompt, cd - is quicker to type, and it also prints the directory it returns to:

$ cd /etc/ssh
$ cd /var/log
$ cd -
/etc/ssh

Listing with ls

ls lists the contents of the working directory, or of the directories and files you name. In a terminal it prints the names in columns; when its output goes into a file or another command, it prints one name per line. ls -1 (the digit one) asks for one per line explicitly, which is what the examples here use.

Option Meaning Example
-l Long format: type, permissions, owner, size, date ls -l /etc/ssh
-a All, including hidden names and . and .. ls -a ~
-A Almost all: hidden names, without . and .. ls -A ~
-h Human-readable sizes (K, M, G), together with -l ls -lh /var/log
-t Sort by modification time, newest first ls -lt /var/log
-S Sort by size, largest first ls -lS ~/Downloads
-r Reverse the sort order ls -ltr (newest last)
-R Recursive: also list every subdirectory ls -R projects
-1 One name per line ls -1
-d Show a directory itself, not its contents ls -ld /tmp

Sorting in action. The example creates three log files of different sizes and gives each a fixed modification time with touch -d:

mkdir logs && cd logs
head -c 300 /dev/zero > app.log
head -c 5000 /dev/zero > access.log
head -c 40 /dev/zero > error.log
touch -d '2026-09-01 08:00' access.log
touch -d '2026-09-15 08:00' app.log
touch -d '2026-09-30 08:00' error.log

echo "By name:";  ls -1
echo "By time:";  ls -1t
echo "By size:";  ls -1S
echo "Smallest first:"; ls -1Sr
By name:
access.log
app.log
error.log
By time:
error.log
app.log
access.log
By size:
access.log
app.log
error.log
Smallest first:
error.log
app.log
access.log

(head -c 300 /dev/zero simply produces 300 bytes to fill the file; && runs cd only if mkdir succeeded.) With -R, ls walks the whole tree below a directory:

mkdir -p site/css site/images
touch site/index.html site/css/style.css site/images/logo.png
ls -R site
site:
css
images
index.html

site/css:
style.css

site/images:
logo.png

The long listing

ls -l shows details that differ on every machine (owner, dates, sizes), so here is an illustrative listing of a home directory, with -a added:

$ ls -la
total 32
drwxr-x--- 4 ana  ana  4096 Sep 30 14:02 .
drwxr-xr-x 4 root root 4096 Sep  2 09:15 ..
-rw------- 1 ana  ana  1284 Sep 30 13:58 .bash_history
-rw-r--r-- 1 ana  ana   220 Sep  2 09:15 .bash_logout
-rw-r--r-- 1 ana  ana  3771 Sep  2 09:15 .bashrc
-rw-r--r-- 1 ana  ana   807 Sep  2 09:15 .profile
drwx------ 2 ana  ana  4096 Sep  2 09:20 .ssh
lrwxrwxrwx 1 ana  ana    19 Sep 28 10:40 current -> projects/website-v2
drwxr-xr-x 4 ana  ana  4096 Sep 28 10:39 projects

This listing and the examples on this page are shown in byte order, as with LC_ALL=C.UTF-8. In English locales, ls, glob sorting and sort ignore dots, dashes and case at first, so your order may differ (here, .profile would come after current); LC_ALL=C gives byte order.

Reading one line from left to right:

Column Example Meaning
Type and permissions drwxr-xr-x First character the file type (below), then read, write and execute for owner, group and others (see Users, Permissions and Access Control)
Link count 4 Number of hard links (for a directory: 2 plus its number of subdirectories)
Owner and group ana ana Who owns the file, and its group
Size 4096 In bytes (with -h: 4.0K); for a directory, the size of the directory entry list, not of its contents
Modification time Sep 28 10:39 Last change of the contents; older files show the year instead of the time
Name current -> projects/website-v2 For a symbolic link, also where it points

total 32 on the first line is the disk space the listed files use, in blocks of 1 KiB. To see how much a whole directory holds, use du -sh (see Logs and Monitoring).

Hidden files

A hidden file is a file or directory whose name starts with a dot, such as .bashrc or .ssh. There is no special attribute: ls and file managers simply leave these names out unless you ask for them. The convention keeps personal settings ("dotfiles") out of the way in your home directory.

mkdir settings && cd settings
touch .bashrc .profile notes.txt
mkdir .config

echo "ls:";    ls -1
echo "ls -a:"; ls -1a
echo "ls -A:"; ls -1A
ls:
notes.txt
ls -a:
.
..
.bashrc
.config
.profile
notes.txt
ls -A:
.bashrc
.config
.profile
notes.txt

The tree command

tree draws a directory and everything below it as a tree. It is not installed by default on most servers; install it with sudo apt install tree (Debian, Ubuntu) or sudo dnf install tree (Fedora, RHEL).

$ tree projects
projects
├── notes
│   └── todo.txt
└── website
    ├── css
    │   └── style.css
    └── index.html

3 directories, 3 files

tree -L 2 limits the depth to two levels, and tree -a includes hidden files. Where tree is missing, ls -R or find gives the same information as a plain list.

File types

Linux does not use the extension to decide what a file is: .txt or .sh is only part of the name, a hint for people. The file system does record a few basic types, and the first character of ls -l shows them:

Character Type Example
- Regular file (text, program, image, anything) /etc/hostname
d Directory /etc
l Symbolic link /bin on current systems
c Character device (data as a stream) /dev/null, /dev/tty
b Block device (storage) /dev/sda, /dev/nvme0n1
s Socket (communication between processes) /run/systemd/notify
p Named pipe (FIFO, first in, first out) Created with mkfifo

stat -c '%F' prints the type in words, and the file command goes further: it looks inside the file to recognize its contents.

mkdir demo && cd demo
mkdir scripts
echo "Meeting at 10:00" > notes.txt
printf '#!/bin/bash\necho "Backup done"\n' > scripts/backup.sh
ln -s notes.txt latest

stat -c '%F: %n' scripts notes.txt latest /dev/null
file notes.txt scripts scripts/backup.sh latest
directory: scripts
regular file: notes.txt
symbolic link: latest
character special file: /dev/null
notes.txt:         ASCII text
scripts:           directory
scripts/backup.sh: Bourne-Again shell script, ASCII text executable
latest:            symbolic link to notes.txt

file recognized the script by its first line, not by .sh. That makes it the right tool for an attachment called invoice.pdf that might not be a PDF (Portable Document Format) file at all. The exact wording can differ slightly between versions of file. Links are explained in Working with Files and Directories.

Spaces and special characters in names

Linux allows almost any character in a file name: only / (the separator) and the null character are forbidden. Names with spaces, brackets or a leading dash are legal, but the shell treats those characters specially, so you must quote or escape them:

mkdir "Project Files"
cd "Project Files"
pwd | sed "s|$HOME|~|"
cd ..
cd Project\ Files                # a backslash escapes one character

touch -- -draft.txt 'budget (final).ods'
ls -1
ls -1 ./-draft.txt
~/Project Files
-draft.txt
budget (final).ods
./-draft.txt
  • Spaces: put the name in quotes or escape each space with \. Tab completion does the escaping for you.
  • Brackets, *, ?, $, &, ;: all mean something to the shell; quote the name.
  • A leading dash: a name such as -draft.txt looks like an option. ls -draft.txt fails with "invalid option". Write ./-draft.txt, or put -- before it: -- tells most commands that no more options follow.