The Linux file system is a unified tree rooted at /. Everything — devices, processes, network sockets — appears as a file somewhere in that tree. Mastering navigation and file operations is the foundation of all Linux work.
The FHS defines where programs, data, and configuration files live. Every major Linux distribution follows this standard.
| Directory | Purpose | Examples |
|---|---|---|
/ | Root of the entire filesystem | Everything starts here |
/bin | Essential user binaries (all users) | ls, cp, mv, bash, cat |
/sbin | System binaries (root/admin use) | fdisk, iptables, reboot |
/etc | System-wide configuration files | sshd_config, fstab, passwd |
/home | User home directories | /home/alice, /home/bob |
/root | Root user's home directory | Separate from /home |
/var | Variable data (grows over time) | /var/log, /var/mail, /var/www |
/tmp | Temporary files (cleared on reboot) | Application scratch space |
/usr | User programs and data (read-only) | /usr/bin, /usr/lib, /usr/share |
/usr/local | Locally compiled software | Programs not from package manager |
/opt | Optional third-party software | /opt/google, /opt/nginx |
/lib | Shared libraries for /bin and /sbin | *.so files, kernel modules |
/dev | Device files | /dev/sda, /dev/null, /dev/tty |
/proc | Virtual FS — kernel/process info | /proc/cpuinfo, /proc/meminfo |
/sys | Virtual FS — hardware/driver info | /sys/class/net, /sys/block |
/boot | Bootloader and kernel files | vmlinuz, initrd, grub/ |
/mnt | Temporary mount points | Manually mounted drives |
/media | Auto-mounted removable media | USB drives, CDs |
/srv | Data for services hosted by system | /srv/http, /srv/ftp |
/bin, /sbin, and /lib are often symlinks to /usr/bin, /usr/sbin, and /usr/lib respectively. The merge simplifies the hierarchy.
pwd tells you exactly where you are in the filesystem. Always run it when you feel lost.
$ pwd /home/alice $ pwd -L # print logical path (follows symlinks as-is) /home/alice $ pwd -P # print physical path (resolves all symlinks) /data/users/alice
ls is your most-used command. Learn every flag.
# Basic listing $ ls # list current directory $ ls /etc # list specific directory $ ls -l # long format (permissions, owner, size, date) $ ls -a # show hidden files (starting with .) $ ls -la # long + hidden (most common combination) $ ls -lh # long + human-readable sizes (KB, MB, GB) $ ls -lah # long + hidden + human readable $ ls -R # recursive — list all subdirectories $ ls -lt # sort by modification time (newest first) $ ls -ltr # sort by time, reversed (oldest first) $ ls -lS # sort by file size (largest first) $ ls -ld /etc # show directory itself, not its contents $ ls --color=auto # colorize output (usually default) $ ls -1 # one file per line $ ls *.conf # wildcard — list only .conf files
$ ls -lah /home/alice total 48K drwxr-xr-x 6 alice alice 4.0K Jun 15 10:23 . drwxr-xr-x 4 root root 4.0K Jun 10 08:00 .. -rw------- 1 alice alice 2.1K Jun 15 09:45 .bash_history -rw-r--r-- 1 alice alice 220 Jun 10 08:00 .bash_logout -rw-r--r-- 1 alice alice 3.5K Jun 10 08:00 .bashrc drwx------ 3 alice alice 4.0K Jun 12 14:30 .ssh -rw-r--r-- 1 alice alice 1.2K Jun 14 16:00 notes.txt drwxr-xr-x 2 alice alice 4.0K Jun 15 10:00 projects
| Field | Example | Meaning |
|---|---|---|
| Type + Permissions | drwxr-xr-x | d=directory, rwx=owner perms, r-x=group, r-x=others |
| Hard links | 6 | Number of hard links to this inode |
| Owner | alice | User who owns the file |
| Group | alice | Group that owns the file |
| Size | 4.0K | File size (human-readable with -h) |
| Timestamp | Jun 15 10:23 | Last modification time |
| Name | projects | File or directory name |
# Absolute paths — start from root / $ cd /etc/nginx # go to /etc/nginx directly $ cd /home/alice/projects # full path from root # Relative paths — start from current location $ cd projects # go into projects/ (relative) $ cd ../ # go up one level (parent directory) $ cd ../../ # go up two levels $ cd ../bob # go up one then into bob/ # Special shortcuts $ cd # go to your home directory $ cd ~ # same — go to home directory $ cd - # go to PREVIOUS directory (toggle) $ cd ~alice # go to alice's home directory (as root)
/ and always work from anywhere. Relative paths depend on your current location. Use pwd to confirm where you are before using relative paths.
| Symbol | Meaning | Example |
|---|---|---|
. | Current directory | ./script.sh runs script here |
.. | Parent directory | cd .. goes up one level |
~ | Home directory | cd ~/Documents |
- | Previous directory | cd - toggles last two dirs |
/ | Root directory | cd / goes to filesystem root |
# mkdir — make directories
$ mkdir projects # create one directory
$ mkdir dir1 dir2 dir3 # create multiple at once
$ mkdir -p a/b/c/d # create nested dirs (no error if exists)
$ mkdir -p /opt/myapp/{logs,config,data} # create multiple subdirs
$ mkdir -m 755 secured_dir # create with specific permissions
$ mkdir -v newdir # verbose — show what's created
# rmdir — remove EMPTY directories only
$ rmdir emptydir # remove if empty
$ rmdir -p a/b/c # remove nested empty dirs
$ rmdir dir1 dir2 # remove multiple empty dirs
# To remove non-empty directories, use rm -r (see below)
# Create empty files $ touch newfile.txt # create empty file (or update timestamp) $ touch file1.txt file2.txt file3.txt # create multiple files $ touch -t 202401011200 file.txt # set timestamp to specific date/time # touch is commonly used to: # 1. Create placeholder files # 2. Update a file's modification time without changing content # 3. Trigger build systems that watch file timestamps
# Copy files $ cp file.txt backup.txt # copy file to new name $ cp file.txt /tmp/ # copy to directory $ cp file1.txt file2.txt /tmp/ # copy multiple files to dir $ cp -v file.txt /tmp/ # verbose — show what's copied # Copy directories $ cp -r projects/ projects_backup/ # recursive — copy directory tree $ cp -a projects/ backup/ # archive mode: -r + preserve perms/times/links $ cp -u file.txt dest/ # only copy if source is newer # Useful flags $ cp -i file.txt dest/file.txt # interactive — ask before overwrite $ cp -n file.txt dest/ # no-clobber — never overwrite $ cp -p file.txt dest/ # preserve timestamps, owner, perms $ cp --backup=numbered file.txt dest/ # make numbered backups
# Rename a file or directory $ mv oldname.txt newname.txt # rename file $ mv old_dir/ new_dir/ # rename directory # Move files $ mv file.txt /tmp/ # move to different directory $ mv file1.txt file2.txt /backup/ # move multiple files $ mv -i file.txt dest/ # ask before overwriting $ mv -n file.txt dest/ # never overwrite existing files $ mv -v file.txt /tmp/ # verbose output $ mv -b file.txt dest/ # backup existing destination file # Move and rename simultaneously $ mv /home/alice/report.txt /var/www/html/annual_report_2024.txt
rm permanently deletes files. Use -i flag when unsure. Never run rm -rf / as root.
# Remove files $ rm file.txt # delete single file $ rm file1.txt file2.txt # delete multiple files $ rm *.log # delete all .log files $ rm -i file.txt # interactive — confirm each deletion $ rm -f file.txt # force — no error if file doesn't exist # Remove directories $ rm -r directory/ # recursive — delete directory and contents $ rm -rf directory/ # force recursive (no prompts) — DANGEROUS $ rm -ri directory/ # recursive interactive (safest for dirs) $ rm -rv directory/ # recursive verbose (see what's deleted) # Safe practice: always use -i for important deletions $ rm -ri /var/www/old_site/ # confirm each file before deleting
find is one of Linux's most powerful commands. It searches in real-time through the filesystem.
# Basic find syntax: find [path] [options] [expression]
# Find by name
$ find /etc -name "*.conf" # find .conf files in /etc
$ find /home -name ".bashrc" # find .bashrc in home dirs
$ find . -name "README.md" # search from current directory
$ find / -iname "nginx.conf" # case-insensitive name search
# Find by type
$ find /var/log -type f # files only
$ find /etc -type d # directories only
$ find /dev -type l # symbolic links only
$ find /tmp -type f -name "*.tmp" # combine type and name
# Find by size
$ find /var -size +100M # files larger than 100MB
$ find /tmp -size -1k # files smaller than 1KB
$ find /home -size +10M -size -1G # between 10MB and 1GB
# Find by time (days)
$ find /var/log -mtime -7 # modified within last 7 days
$ find /tmp -mtime +30 # modified more than 30 days ago
$ find /home -atime -1 # accessed within last 24 hours
$ find /etc -ctime -1 # inode changed within last 24 hours
# Find by permissions
$ find / -perm -4000 -type f # find SUID files (security check)
$ find /home -perm 777 # find world-writable files
$ find /etc -perm /o+w # files writable by others
# Find by owner
$ find /home -user alice # files owned by alice
$ find /tmp -group www-data # files owned by www-data group
$ find / -nouser # files with no valid owner
# Execute a command on results
$ find /var/log -name "*.log" -exec ls -lh {} \; # ls each log file
$ find /tmp -mtime +7 -exec rm {} \; # delete old tmp files
$ find . -name "*.py" -exec grep -l "import os" {} \; # grep in results
# Find and delete (safer alternative to -exec rm)
$ find /tmp -mtime +30 -delete # delete files older than 30 days
# Exclude directories
$ find / -name "*.conf" -not -path "*/proc/*" # skip /proc
# Combine with OR / AND
$ find . -name "*.txt" -or -name "*.md" # either extension
$ find . -name "*.log" -and -size +10M # both conditions
# file — determine file type (doesn't use extension) $ file /bin/ls /bin/ls: ELF 64-bit LSB pie executable, x86-64 $ file /etc/passwd /etc/passwd: ASCII text $ file /dev/sda /dev/sda: block special (8/0) $ file image.jpg image.jpg: JPEG image data, JFIF standard 1.01 $ file script.sh script.sh: Bourne-Again shell script, ASCII text executable $ file archive.tar.gz archive.tar.gz: gzip compressed data # stat — detailed inode information $ stat /etc/passwd File: /etc/passwd Size: 2847 Blocks: 8 IO Block: 4096 regular file Device: 801h/2049d Inode: 659370 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-06-15 09:23:01.123456789 +0000 Modify: 2024-06-10 14:00:00.000000000 +0000 Change: 2024-06-10 14:00:00.000000000 +0000 Birth: -
The shell expands wildcards before passing arguments to commands. This is called "globbing."
| Pattern | Matches | Example |
|---|---|---|
* | Zero or more characters | *.log matches app.log, error.log |
? | Exactly one character | file?.txt matches file1.txt, fileA.txt |
[abc] | One character from the set | file[123].txt matches file1, file2, file3 |
[a-z] | One character from range | [a-z]*.txt matches files starting a-z |
[^abc] | One char NOT in set | [^0-9]* matches non-digit starts |
{a,b,c} | Brace expansion (any of) | {jpg,png,gif} expands to each |
# Practical wildcard examples
$ ls *.txt # all .txt files
$ ls file?.sh # file1.sh, file2.sh, filea.sh
$ ls [A-Z]*.conf # .conf files starting with uppercase
$ rm *.{tmp,bak,swp} # delete temp/backup/swap files
$ cp /etc/{passwd,group,shadow} /backup/ # copy specific files
$ ls /var/log/{nginx,apache2}/ # list from multiple dirs
$ touch report_{jan,feb,mar}_2024.txt # create 3 files at once
# Press Tab to auto-complete commands and paths $ cd /home/al[TAB] # completes to /home/alice/ if unique $ systemctl st[TAB][TAB] # shows: start, status, stop, ... # Double Tab shows all possibilities $ ls /etc/ss[TAB][TAB] ssh/ ssl/ sssd/
# View and use history $ history # show numbered command history $ history 20 # show last 20 commands $ history | grep find # search history for 'find' # History shortcuts $ !! # repeat last command $ !234 # run command number 234 from history $ !ssh # run last command starting with 'ssh' $ !$ # last argument of previous command $ !* # all arguments of previous command $ ^old^new # replace 'old' with 'new' in last command # History search: press Ctrl+R and type to search backwards (reverse-i-search)`ssh': ssh alice@192.168.1.100 # History settings in ~/.bashrc HISTSIZE=10000 # commands to keep in memory HISTFILESIZE=20000 # commands to keep in file HISTCONTROL=ignoredups # don't store duplicate commands
| Shortcut | Action |
|---|---|
| Ctrl+C | Kill current running command |
| Ctrl+Z | Suspend current command (send to background) |
| Ctrl+D | End of input / logout from shell |
| Ctrl+L | Clear screen (same as clear command) |
| Ctrl+A | Move cursor to beginning of line |
| Ctrl+E | Move cursor to end of line |
| Ctrl+W | Delete word before cursor |
| Ctrl+U | Delete everything before cursor |
| Ctrl+K | Delete everything after cursor |
| Ctrl+R | Reverse search through history |
| Alt+. | Insert last argument of previous command |
| Up/Down arrows | Navigate command history |
# Scenario: you're a sysadmin investigating a web server
# 1. Find where you are
$ pwd
/root
# 2. Check disk usage first
$ du -sh /var/log
1.2G /var/log
# 3. Navigate to log directory
$ cd /var/log
# 4. List logs sorted by size
$ ls -lhS
total 1.2G
-rw-r--r-- 1 root root 890M Jun 15 nginx/access.log
-rw-r--r-- 1 root adm 120M Jun 15 syslog
-rw-r--r-- 1 www www 45M Jun 15 apache2/error.log
# 5. Find logs modified today
$ find /var/log -mtime 0 -type f
# 6. Find large log files
$ find /var/log -size +50M -type f -exec ls -lh {} \;
# 7. Check file type before reading
$ file /var/log/nginx/access.log
/var/log/nginx/access.log: ASCII text, with very long lines
# 8. Go back to where you were
$ cd -
/root