Skip to content

Files & Directories

When you first log into a system or open a terminal, the default directory is your home directory. You can print its exact path with echo $HOME.

CommandResult
pwdPrint present working directory
cd ~ or cdChange to home directory (~ = tilde = shortcut)
cd ..Change to parent directory
cd -Change to previous directory (toggle)
cd /usr/binChange using absolute path

Relative and absolute path

There are two ways to identify filesystem paths:

  • Absolute pathname - begins with / (root); follows the tree from root. Always works regardless of where you are.
  • Relative pathname - starts from the present working directory; never begins with /
Terminal window
# Both change from home to /usr/bin:
cd /usr/bin # absolute - unambiguous
cd ../../usr/bin # relative - depends on where you are now
# Multiple slashes are legal but collapsed:
# ////usr//bin == /usr/bin

Useful special paths:

  • . - the present directory
  • .. - the parent directory
  • ~ - your home directory
Terminal window
ls # list current directory contents
ls -l # long format: permissions, links, owner, group, size, date
ls -la # include hidden files (dot-files)
ls -lh # human-readable file sizes (K, M, G)
ls -lS # sort by size, largest first
ls -lt # sort by modification time (mtime), newest first
ls -ltu # sort by access time (atime), newest first
ls -ltc # sort by metadata change time (ctime), newest first
ls -lR # recursive - list all subdirectories
ls -ali # include inode numbers
ls -ald # list directories themselves, not their contents
ls -n # show UID/GID numbers instead of names
tree # visual directory tree
tree -d # directories only
-rw-r--r-- 1 root testuser 42118 Jun 11 07:18 File-01.txt
│ │ │ │ │ │ │
│ │ │ │ │ │ └─ filename
│ │ │ │ │ └─ last modification time
│ │ │ │ └─ size in bytes
│ │ │ └─ group
│ │ └─ owner
│ └─ hard link count
└─ permissions (type + user + group + other)

Linux tracks three timestamps per file:

TimestampNameUpdated when
atimeAccess timeFile is read
mtimeModification timeFile content changes
ctimeChange timeMetadata changes (permissions, ownership, location)

This distinction matters when you use find or ls sorting options:

Terminal window
touch theNewestFile # creates file → updates atime AND ctime
echo "hello" > file-02 # write content → updates mtime AND ctime
chmod 444 file-01 # change permissions → updates ctime only
Terminal window
pushd /var/log # push current dir to stack, cd to /var/log
pushd /etc # push /var/log, cd to /etc
dirs # show directory stack
popd # pop stack → returns to /var/log
popd # pop stack → returns to original directory

/usr/bin/diff
which diff # exact location of the binary
whereis diff # binary + man page + source
# diff: /usr/bin/diff /usr/share/man/man1/diff.1.gz

which searches $PATH. whereis casts a wider net, searching standard system directories.

CommandBest for
cat fileShort files; printing to stdout
tac fileSame, but lines in reverse order
less fileLarge files; scroll up/down, search with /
head -n 20 fileFirst 20 lines (default: 10)
tail -n 20 fileLast 20 lines (default: 10)
tail -f fileFollow a growing file in real-time (perfect for logs)
Terminal window
# Common workflows
grep ERROR /var/log/syslog | tail -50 # last 50 errors
tail -f /var/log/nginx/access.log # live request monitoring
cat file1 file2 > combined.txt # concatenate two files
Terminal window
touch newfile # create empty file (or update timestamps if exists)
touch -t 12091600 myfile # set timestamp to Dec 9, 4:00pm
# Interactive write with cat:
cat > newfile # type content, Ctrl-D to save
cat >> existingfile # append to existing file
cat > newfile << EOF # heredoc style (type until EOF line)
Hello world
EOF
Terminal window
mkdir sampdir # create directory
mkdir -p parent/child{01..10} # create parent + 10 children at once
mkdir testdir1 testdir2 testdir3 # multiple at once
rmdir emptydir # remove empty directory only
rm -rf mydir # recursively remove dir and all contents
Terminal window
mv file.txt newname.txt # rename
mv file.txt /tmp/ # move to directory
mv file.txt /tmp/newname.txt # move and rename in one step
rm file.txt # remove file
rm -f file.txt # force remove (no error if missing)
rm -i *.log # interactive - confirm each deletion

locate uses a pre-built database for instant searches - much faster than find for simple lookups.

Terminal window
locate zip # find all paths containing "zip"
locate zip | grep bin # filter to paths with both "zip" and "bin"
sudo updatedb # manually refresh the database (auto-runs daily)

find recursively walks the filesystem in real time. Default path is the current directory.

Terminal window
# Basic search
find /usr -name gcc # find files named "gcc" under /usr
find /usr -type d -name gcc # only directories
find /usr -type f -name gcc # only regular files
find . -name "*.swp" # find by pattern
# By time
find / -ctime 3 # ctime changed exactly 3 days ago
find / -mtime -7 # modified within last 7 days
find / -mmin -60 # modified within last 60 minutes
# By size
find / -size +10M # files larger than 10 MB
find / -size 0 # empty files
# Execute a command on results
find . -name "*.swp" -exec rm {} ';' # delete all .swp files
find . -name "*.log" -ok rm {} ';' # interactive: confirm before each delete
  • -exec runs the command immediately on every match
  • -ok is like -exec but prompts for confirmation - good for testing dangerous commands
  • {} is replaced with the matched filename
  • ';' terminates the -exec command (single-quoted to protect from shell)

Used in shell globbing (filename pattern matching) - not the same as regex:

WildcardMatches
?Any single character
*Any string of characters (including empty)
[set]Any single character in the set: [adf]
[!set]Any character NOT in the set
Terminal window
ls ba?.out # three-letter filename starting with "ba", ending in ".out"
ls *.log # all files ending in ".log"
ls file[0-9].txt # file0.txt through file9.txt
rm temp[!0-9]* # remove files starting with temp NOT followed by a digit

The ln utility creates links - additional name entries pointing to the same data.

Terminal window
ln file1 file2
ls -li file1 file2
# 49302296 -rw-r--r-- 2 student student 0 Oct 24 2024 file1
# 49302296 -rw-r--r-- 2 student student 0 Oct 24 2024 file2

The -i flag shows inode numbers. Both files have the same inode (49302296) - they are the same file, just two name entries. The 2 in the link count column means two hard links point to this inode.

Key properties of hard links:

  • Same inode, same data, different names
  • Deleting file1 leaves file2 intact - the data is removed only when the last link is deleted
  • Cannot span filesystems or partitions
  • Cannot link to directories (prevents loops)
Terminal window
ln -s file1 file3
ls -li file1 file3
# 49302296 -rw-r--r-- 2 student student 0 Oct 24 2024 file1
# 49302397 lrwxrwxrwx 1 student student 5 Oct 24 2024 file3 -> file1

file3 has a different inode - it is a separate filesystem object that simply points to file1. The l type indicator and -> file1 in the listing confirm it’s a symlink.

Key properties of soft links:

  • Different inode from target; tiny amount of storage (stores the target path)
  • Can span filesystems, partitions, and even network mounts
  • Can point to directories
  • If the target is deleted or moved, the symlink becomes dangling (broken)
Terminal window
ln -s /var/log/nginx/access.log ~/nginx-access.log # shortcut to long path
ln -s /opt/myapp/bin/myapp /usr/local/bin/myapp # put binary in PATH