A Comprehensive Reference — 200+ Commands
Ubuntu Terminal
Handbook
Core bash, system administration, and scripting — Ubuntu 22.04 & 24.04 LTS, Bash 5.x
Contents — 25 Sections
►25 Sections — 200+ Commands
- Getting Help & Navigation
- File System Operations
- Text & File Content
- Process Management
- Service Management
- System Information
- User & Group Management
- Network Commands
- Permissions & Ownership
- Variables & Data Types
- String Manipulation
- Pipelines & Filtering
- Loops & Conditionals
- Functions & Scripts
- Error Handling
- Output & Formatting
- Scheduled Tasks
- Logging & Journald
- Security & Permissions
- Remote Access & SSH
- Package Management
- Environment Variables
- Date & Time
- Math & Numbers
- Aliases & Shell Config
1. Getting Help & Navigation
►Discovery and navigation tools — how to find out what a command does and move around the file system without leaving the shell.
man ls
man 5 passwd # section 5: file formats
man -k network # same as apropos
man -f printf # same as whatis
Key flags: -k (keyword search), section numbers 1–8 disambiguate commands from config files and syscalls
--help for a quick option summary, faster than a full man page.ls --help
tar --help | less
systemctl --help
apropos copy
apropos "list directory"
whatis ls
whatis -a printf
info coreutils
info bash
info gcc
type cd # cd is a shell builtin
which python3 # /usr/bin/python3
whereis gcc # binary, source and man page paths
Key flags: type is the most reliable since it understands aliases and functions; which only finds binaries on PATH
pwd
pwd -P # resolve symlinks to the real path
cd /var/log
cd ~ # home directory
cd - # previous directory
cd .. # parent directory
cd # no args also goes home
pushd /etc/nginx
# ...do work...
popd # back to where you started
dirs -v # view the stack
!! and Ctrl+R it is one of the biggest time-savers in the shell.history | tail -20
!! # re-run the last command
sudo !! # re-run last command with sudo
!423 # re-run history entry 423
Key flags: Ctrl+R starts a reverse incremental search through history
2. File System Operations
►Creating, copying, moving, and inspecting files and directories — the bread and butter of working in a terminal.
| Command | Common flags | Description |
|---|---|---|
ls | -la -lh -lt -R | Lists files and directories |
cp | -r -p -v -a | Copies files and directories |
mv | -v -n | Moves or renames files and directories |
rm | -r -f -v -i | Deletes files and directories |
mkdir | -p -v | Creates directories |
rmdir | — | Removes empty directories |
touch | -t | Creates empty files or updates timestamps |
ln | -s | Creates hard or symbolic links |
stat | — | Shows detailed file metadata |
file | — | Identifies file type by content, not extension |
ls -la # all files including hidden, long format
ls -lh # human-readable sizes (K/M/G)
ls -lt # sort by modification time, newest first
ls -R # recurse into subdirectories
ls -d */ # list only directories
find <path> [-name|-iname <pattern>] [-type f|d] [-mtime <n>] [-size <n>] [-exec <cmd> {} \;]
find . -name "*.log"
find /var -type f -mtime -1 # modified in the last day
find . -type f -size +100M
find . -name "*.tmp" -delete
find . -name "*.sh" -exec chmod +x {} \;
Key flags: -iname (case-insensitive), -maxdepth (limit recursion), -mtime -n / +n (newer/older than n days)
cp -r ~/project /backup/
cp -a src/ dest/ # archive mode: preserves permissions, timestamps, symlinks
mv old-name.txt new-name.txt
mv *.jpg ~/Pictures/
rm file.txt
rm -r old-folder/
rm -i *.tmp # prompt before each deletion
rm -rf is irreversible and will not ask for confirmation. Double-check the path before pressing enter, especially with wildcards or as root.mkdir new-folder
mkdir -p projects/2026/website/assets # creates the whole chain
ln -s /opt/app/current /usr/local/bin/app # symlink
ln original.txt hardlink.txt # hard link
Key flags: Symlinks can cross filesystems and point to directories; hard links cannot
du measures specific files or directories; df reports free space per mounted filesystem.du -sh ~/Downloads # total size of a folder
du -h --max-depth=1 /var # one level of subfolders
df -h # free space on all mounts
stat report.pdf
file mystery-file # e.g. "ELF 64-bit LSB executable"
3. Text & File Content
►Reading, searching, and transforming text — whether that's a config file, a CSV, or a live log stream.
cat dumps the whole file; less pages through it interactively (preferred for anything long).cat notes.txt
cat file1.txt file2.txt > combined.txt
less /var/log/syslog # q to quit, / to search
tail -f follows a growing file live — the standard way to watch a log in real time.head -20 access.log
tail -50 access.log
tail -f /var/log/nginx/error.log # live follow, Ctrl+C to stop
tail -n +100 file.txt # everything from line 100 onward
grep [-i -v -r -n -c -E] '<pattern>' <file>
grep -i "error" app.log
grep -rn "TODO" ./src
grep -v "^#" config.conf # exclude commented lines
grep -E "warn|error" app.log # extended regex, multiple patterns
grep -c "404" access.log # count matching lines
Key flags: -i case-insensitive, -r recursive, -v invert match, -n show line numbers, -E extended regex
sed 's/old/new/' file.txt # replace first match per line
sed 's/old/new/g' file.txt # replace all matches per line
sed -i 's/foo/bar/g' file.txt # edit the file in place
sed -n '10,20p' file.txt # print only lines 10-20
Key flags: -i edit in place (use -i.bak to keep a backup), -n with p suppresses default output
awk '{print $1}' access.log # first column
ps aux | awk '{print $2, $11}' # PID and command
awk -F',' '{print $2}' data.csv # custom field separator
awk '$3 > 100 {print}' report.txt # conditional print
sort names.txt
sort -n numbers.txt # numeric sort
sort -r file.txt # reverse order
sort file.txt | uniq # remove duplicate lines
sort file.txt | uniq -c | sort -rn # count and rank occurrences
cut -d',' -f2 data.csv # second comma-separated field
echo "hello" | tr 'a-z' 'A-Z' # uppercase
wc -l file.txt # line count
wc -w file.txt # word count
diff old.conf new.conf
diff -u old.conf new.conf # unified diff, the format used by patches
4. Process Management
►Inspecting, controlling, and managing the lifecycle of running processes — foreground, background, and persistent.
ps aux # everyone's processes, full detail
ps aux | grep nginx
ps -ef --forest # tree view showing parent/child relationships
Key flags: aux (BSD style, most common), -ef (UNIX style)
htop is a friendlier, colour version (install with apt if not present).top
htop
top -o %MEM # sort by memory usage
Key flags: Inside top: q quit, k kill a process, M sort by memory, P sort by CPU
kill 1234 # graceful SIGTERM
kill -9 1234 # force kill, SIGKILL
killall firefox # kill by name
pkill -f "python script.py" # kill by matching the full command line
Key flags: Try a plain kill first; reach for -9 only when the process won't respond
long-task.sh & # start in background
jobs # list background jobs
fg %1 # bring job 1 to the foreground
bg %1 # resume job 1 in the background
Ctrl+Z # suspend the foreground job
nohup ./long-task.sh &
disown -h %1 # detach an already-running job from the shell
Key flags: nohup redirects output to nohup.out by default; combine with > to redirect elsewhere
nice -n 10 ./batch-job.sh
renice -n 5 -p 1234
lsof -i :8080 # what's using port 8080
lsof /var/log/syslog # what has this file open
ps through grep.pgrep nginx
pidof sshd
5. Service Management
►Controlling systemd services — the standard init system on Ubuntu since 15.04.
| Action | Command |
|---|---|
| Check status | systemctl status nginx |
| Start | sudo systemctl start nginx |
| Stop | sudo systemctl stop nginx |
| Restart | sudo systemctl restart nginx |
| Reload config without restart | sudo systemctl reload nginx |
| Enable at boot | sudo systemctl enable nginx |
| Disable at boot | sudo systemctl disable nginx |
| Check if active | systemctl is-active nginx |
| Check if enabled | systemctl is-enabled nginx |
systemctl list-units --type=service --state=running
systemctl list-units --type=service --state=failed
systemctl --failed
.service file. Required before changes take effect.sudo systemctl daemon-reload
sudo systemctl restart myapp.service
systemctl is preferred on any modern Ubuntu release.sudo service nginx restart
journalctl -u <service> to see a service's logs — covered in Section 18, Logging & Journald.6. System Information
►Hardware, OS, and kernel information — the equivalent of opening Task Manager and System Properties combined.
uname -a # everything
uname -r # kernel release only
uname -m # architecture (x86_64, aarch64...)
hostnamectl
sudo hostnamectl set-hostname new-name
cat /etc/os-release
lsb_release -a
lscpu
nproc # number of available processing units
free -h # human-readable
watch -n 1 free -h # refresh every second
lsblk
lsblk -f # include filesystem type and UUID
df -h
lsusb
lspci
lspci -k # show which kernel driver each device uses
uptime
vmstat 1 5 # 5 samples, 1 second apart
dmesg | tail -50
dmesg -T | grep -i usb # human-readable timestamps
7. User & Group Management
►Creating, modifying, and inspecting local user accounts and groups on a standalone Ubuntu machine.
adduser is the friendlier, interactive Debian/Ubuntu wrapper; useradd is the lower-level, scriptable version.sudo adduser jdoe # interactive, prompts for password and details
sudo useradd -m -s /bin/bash jdoe # -m creates home dir, -s sets shell
passwd # change your own password
sudo passwd jdoe # set another user's password
sudo passwd -l jdoe # lock the account
sudo passwd -u jdoe # unlock it
sudo usermod -aG sudo jdoe # add to a group (note -a, otherwise existing groups are wiped)
sudo usermod -L jdoe # lock account
sudo usermod -s /bin/zsh jdoe # change default shell
Key flags: Always use -aG not -G alone — -G without -a replaces all existing group memberships
sudo deluser jdoe
sudo deluser --remove-home jdoe # also delete their home directory
sudo groupadd developers
sudo gpasswd -a jdoe developers # add user to group
sudo gpasswd -d jdoe developers # remove user from group
id
id jdoe
groups jdoe
who
w # who, plus what they're running
last -10 # last 10 login sessions
su switches users entirely; sudo runs a single command with elevated privileges, logging the action.su - jdoe # switch user with their full login environment
sudo apt update
sudo -i # root shell with root's environment
sudo -u jdoe whoami # run a command as a specific user
sudo chage -l jdoe # list current ageing settings
sudo chage -M 90 jdoe # force password change every 90 days
8. Network Commands
►Testing connectivity, inspecting interfaces, querying DNS, and transferring data over the network.
ping google.com
ping -c 4 192.168.1.1 # stop after 4 packets
ifconfig and route.ip addr show # all interfaces and their IPs (or 'ip a')
ip route show # routing table, including default gateway
ip link set eth0 up # bring an interface up
ip -s link # interface statistics
netstat.ss -tulpn # all listening TCP/UDP sockets with process names
ss -t state established # established TCP connections only
Key flags: -t TCP, -u UDP, -l listening, -p show process, -n numeric (skip DNS lookups)
curl https://example.com
curl -O https://example.com/file.zip # save with the remote filename
curl -I https://example.com # headers only
curl -X POST -d '{"key":"val"}' -H "Content-Type: application/json" https://api.example.com
wget https://example.com/file.iso
wget -c https://example.com/big-file.zip # resume a partial download
dig example.com
dig example.com MX
dig +short example.com # just the answer, no preamble
host example.com
mtr combines ping and traceroute into a live updating view.traceroute google.com
mtr google.com # interactive, q to quit
nc -zv example.com 443 # test if a port is open
nc -l 9000 # listen on a port
ip addr output.hostname -I
9. Permissions & Ownership
►Linux's permission model and ownership tools — who can read, write, or run what.
| Symbol | Permission | Meaning on a file | Meaning on a directory |
|---|---|---|---|
r | Read (4) | View file contents | List directory contents |
w | Write (2) | Modify or delete file contents | Add or remove files inside it |
x | Execute (1) | Run the file as a program/script | Enter (cd into) the directory |
chmod [ugoa][+-=][rwx] <file> | chmod <octal> <file>
chmod +x script.sh # add execute for everyone
chmod 755 script.sh # rwxr-xr-x
chmod 644 config.txt # rw-r--r--
chmod -R 755 ./website/ # recursively
chmod u+w,g-w file.txt # symbolic: user write on, group write off
Key flags: Octal digits: read 4, write 2, execute 1 — sum them per owner/group/other (e.g. 7=rwx, 5=r-x, 4=r--)
sudo chown jdoe file.txt
sudo chown jdoe:developers file.txt # user and group together
sudo chown -R www-data:www-data /var/www/html
sudo chgrp developers file.txt
umask # show current mask, e.g. 0022
umask 077 # new files private to the owner only
Key flags: The mask is subtracted from the system default (666 for files, 777 for directories)
getfacl file.txt
setfacl -m u:jdoe:rw file.txt # grant jdoe read/write
setfacl -x u:jdoe file.txt # remove that entry
chmod +t, seen as t in /tmp's permissions) means only a file's owner can delete it, even if others can write to the containing directory. SUID/SGID (chmod u+s / g+s) make a program run with the file owner's/group's privileges rather than the caller's — powerful, and a common attack surface if misused.10. Variables & Data Types
►Storing and working with data in the shell — scalar variables, arrays, and bash's special built-in variables.
name="Alice"
count=42
echo "Hello, $name"
export PATH="$PATH:/opt/tool/bin" # make visible to child processes
readonly API_KEY="abc123" # cannot be changed after this
unset name
Key flags: export makes a variable available to subprocesses; without it, it's local to the current shell only
$0 # script name
$1 $2 ... # positional arguments
$# # number of arguments
$@ # all arguments as separate words
$? # exit status of the last command
$$ # current process ID
$RANDOM # a random integer
fruits=(apple banana cherry)
echo ${fruits[0]} # apple
echo ${fruits[@]} # all elements
echo ${#fruits[@]} # array length, 3
fruits+=(date) # append an element
for f in "${fruits[@]}"; do echo "$f"; done
-A (bash 4+).declare -A config
config[host]="db01"
config[port]=5432
echo ${config[host]}
for key in "${!config[@]}"; do echo "$key: ${config[$key]}"; done
expr for most cases.count=5
(( count++ ))
(( total = count * 10 ))
if (( count > 3 )); then echo "big"; fi
11. String Manipulation
►Bash's built-in parameter expansion syntax for trimming, replacing, and reformatting strings without external tools.
| Operation | Syntax / example | Notes |
|---|---|---|
| Length | ${#var} | Number of characters |
| Substring | ${var:5:3} | Offset 5, length 3 |
| Remove prefix | ${var#pattern} | Shortest match; ## for longest |
| Remove suffix | ${var%pattern} | Shortest match; %% for longest |
| Replace first match | ${var/find/replace} | Case-sensitive |
| Replace all matches | ${var//find/replace} | Global |
| Default value | ${var:-default} | Use 'default' only if var is unset/empty |
| Uppercase | ${var^^} | Lowercase: ${var,,} |
| Default if unset | ${var:=default} | Also assigns the default to var |
path="/home/conor/report.txt"
echo ${path##*/} # report.txt — strip everything up to the last slash
echo ${path%.*} # /home/conor/report — strip the extension
name="Conor"
echo "Hello, ${name^^}!" # Hello, CONOR!
grep "error" <<< "$log_line"
printf "%-10s %5d\n" "Name:" 42
printf "%s\n" "${fruits[@]}" # one per line
sed or awk (covered in Section 3) rather than fighting with nested parameter expansions.12. Pipelines & Filtering
►Chaining small commands into pipelines — the core idiom that makes the shell more powerful than any single tool.
ps aux | grep nginx | awk '{print $2}'
cat access.log | grep "404" | wc -l
rm or cp).find . -name "*.tmp" | xargs rm
find . -name "*.log" | xargs -I{} mv {} ./archive/
echo "file1 file2" | xargs -n1 echo # one arg at a time
Key flags: -I{} lets you place the input anywhere in the command, not just at the end
long-task.sh | tee output.log
echo "new line" | sudo tee -a /etc/some.conf # -a appends, sudo with tee for protected files
$(...) preferred over the older backtick syntax.today=$(date +%Y-%m-%d)
files=$(ls *.txt | wc -l)
echo "There are $(nproc) CPU cores"
diff <(sort file1.txt) <(sort file2.txt)
comm <(ls dirA) <(ls dirB)
comm), or merges lines from multiple files side by side (paste).comm <(sort a.txt) <(sort b.txt) # 3 columns: only in a, only in b, in both
paste names.txt scores.txt # tab-joined columns
13. Loops & Conditionals
►Branching and repeating logic in shell scripts — the building blocks of any automation.
test ([ ]) or the more modern [[ ]].if [[ $count -gt 10 ]]; then
echo "big"
elif [[ $count -gt 5 ]]; then
echo "medium"
else
echo "small"
fi
Key flags: Comparisons: -eq -ne -gt -lt -ge -le (numbers), == != (strings, inside [[ ]]), -z (empty string), -f -d (file/directory exists)
[[ ]] over [ ] in bash scripts — it supports &&/|| inside the brackets, pattern matching, and doesn't require quoting variables to avoid word-splitting bugs.case "$1" in
start) echo "Starting..." ;;
stop) echo "Stopping..." ;;
*.log) echo "A log file" ;;
*) echo "Unknown option" ;;
esac
for f in *.txt; do echo "$f"; done
for i in {1..10}; do echo $i; done
for ((i=0; i<5; i++)); do echo $i; done # C-style
while) or until it becomes true (until).i=0
while (( i < 5 )); do
echo $i
(( i++ ))
done
until ping -c1 server01 &>/dev/null; do sleep 2; done # poll until reachable
for i in {1..10}; do
[[ $i -eq 5 ]] && break
[[ $((i % 2)) -eq 0 ]] && continue
echo $i
done
14. Functions & Scripts
►Writing reusable functions and standalone scripts — turning one-off commands into repeatable tools.
function keyword or just parentheses.greet() {
local name="${1:-World}"
echo "Hello, $name!"
}
greet Alice
function cleanup {
rm -rf /tmp/build-cache
}
Key flags: local scopes a variable to the function only, preventing it leaking into the rest of the script
$1, $@, and $#, separate from the script's own arguments.backup() {
local src="$1"
local dest="$2"
cp -r "$src" "$dest"
}
backup ~/docs /backup/docs
#!/bin/bash
chmod +x deploy.sh
./deploy.sh
Key flags: #!/usr/bin/env bash is more portable across systems where bash isn't always at /bin/bash
source ./functions.sh
. ./functions.sh # identical, the dot is shorthand
# vs. ./script.sh which runs in a separate subshell
while getopts "f:v" opt; do
case $opt in
f) file="$OPTARG" ;;
v) verbose=true ;;
esac
done
# usage: ./script.sh -f input.txt -v
script_dir="$(dirname "${BASH_SOURCE[0]}")"
config="$script_dir/config.json"
15. Error Handling
►Detecting and responding to failure in scripts — exit codes, safety flags, and cleanup on exit.
0 means success; any non-zero value means something went wrong, and the specific number is command-defined.grep "error" app.log
echo $? # 0 if found, 1 if not found, 2 on a real error
ping -c1 server01 &>/dev/null
if [[ $? -eq 0 ]]; then echo "reachable"; fi
&&) or only on failure (||).mkdir -p build && cd build && make
ping -c1 server01 || echo "server01 is down"
#!/bin/bash
set -euo pipefail
# -e: exit immediately if any command fails
# -u: error on use of an unset variable
# -o pipefail: a pipeline fails if any stage fails, not just the last one
trap 'rm -f /tmp/lockfile' EXIT
trap 'echo "Interrupted"; exit 1' INT TERM
if [[ ! -f "$config" ]]; then
echo "Config not found" >&2
exit 1
fi
16. Output & Formatting
►Controlling where output goes and how it's formatted — redirection, here-docs, and tidy column output.
printf gives precise control over formatting; echo is quicker for simple cases.echo "Hello, World!"
echo -e "Line1\nLine2" # -e enables backslash escapes
printf "%-10s %5d\n" "Total:" 42
| Redirection | Meaning |
|---|---|
> file | Redirect stdout to a file, overwriting it |
>> file | Redirect stdout to a file, appending |
< file | Use a file as stdin |
2> file | Redirect stderr only |
&> file | Redirect both stdout and stderr |
2>&1 | Merge stderr into stdout's destination |
command > /dev/null 2>&1 | Discard all output |
cat <<EOF > config.txt
host=db01
port=5432
EOF
mysql -u root <<SQL
SHOW DATABASES;
SQL
cat /etc/passwd | column -t -s ':'
ps aux | column -t
17. Scheduled Tasks
►Running commands automatically on a schedule — cron, one-off jobs, and the modern systemd timer alternative.
| Field | Allowed values |
|---|---|
| Minute | 0-59 |
| Hour | 0-23 |
| Day of month | 1-31 |
| Month | 1-12 |
| Day of week | 0-7 (0 and 7 are both Sunday) |
crontab -e # edit your crontab
crontab -l # list current entries
0 2 * * * /home/conor/scripts/backup.sh # every day at 2am
*/15 * * * * /home/conor/scripts/healthcheck.sh # every 15 minutes
0 9 * * 1 /home/conor/scripts/weekly-report.sh # 9am every Monday
at 10pm
at> /home/conor/scripts/shutdown-check.sh
at> Ctrl+D
atq # list pending at jobs
atrm 3 # cancel job 3
.timer units paired with a .service unit, with the advantage of full systemd logging via journalctl.systemctl list-timers
# /etc/systemd/system/backup.timer:
# [Timer]
# OnCalendar=daily
# [Install]
# WantedBy=timers.target
sudo systemctl enable --now backup.timer
/etc/cron.d/ rather than editing a user's crontab directly — useful for jobs installed by packages or configuration management.18. Logging & Journald
►Finding out what happened and when — the systemd journal, traditional log files, and writing your own log entries.
journalctl -u nginx # logs for one service
journalctl -u nginx -f # follow live, like tail -f
journalctl -b # logs since the current boot
journalctl --since "1 hour ago"
journalctl -p err # priority: err and above only
Key flags: -u unit, -f follow, -b this boot, -p priority (emerg, alert, crit, err, warning, notice, info, debug)
less /var/log/syslog
tail -f /var/log/auth.log # authentication and sudo attempts
zcat /var/log/syslog.1.gz | less # rotated, compressed logs
logger "Backup script completed successfully"
logger -t mybackup -p user.warning "Backup took longer than expected"
logrotate, configured in /etc/logrotate.d/. You shouldn't normally need to touch it, but it's worth knowing it's there when disk space questions come up.19. Security & Permissions
►Locking things down — privilege escalation, the firewall, key-based authentication, and encryption.
/var/log/auth.log.sudo apt update
sudo -l # list what you're allowed to run
sudo -v # refresh your sudo timestamp without running a command
/etc/sudoers with syntax checking, preventing a typo from locking everyone out of sudo.sudo visudo
sudo visudo -f /etc/sudoers.d/jdoe # edit a drop-in file instead (preferred)
sudo ufw status verbose
sudo ufw allow 22/tcp # allow SSH
sudo ufw allow from 192.168.1.0/24 to any port 5432
sudo ufw deny 23
sudo ufw enable
ssh-keygen -t ed25519 -C "conor@cmr-rig"
cat ~/.ssh/id_ed25519.pub # the public key to share/install
gpg --gen-key
gpg -e -r recipient@example.com secret.txt # encrypt for a recipient
gpg -d secret.txt.gpg # decrypt
apt; not present by default.sudo apt install fail2ban
sudo fail2ban-client status sshd
20. Remote Access & SSH
►Connecting to, copying files to, and working persistently on remote machines over SSH.
ssh jdoe@server01
ssh -p 2222 jdoe@server01 # non-default port
ssh -i ~/.ssh/custom_key jdoe@server01
ssh jdoe@server01 "df -h" # run one command remotely, no interactive session
authorized_keys, enabling passwordless login afterwards.ssh-copy-id jdoe@server01
# ~/.ssh/config
Host rig
HostName 192.168.1.50
User conor
Port 2222
IdentityFile ~/.ssh/rig_key
ssh rig # now just this
scp report.pdf jdoe@server01:/home/jdoe/
scp jdoe@server01:/var/log/app.log ./
scp -r ./website/ jdoe@server01:/var/www/
scp for large or repeated transfers.rsync -avz ./project/ jdoe@server01:/backup/project/
rsync -avz --delete ./local/ remote:/dest/ # mirror exactly, removing extras on the destination
rsync --dry-run -avz ./local/ remote:/dest/ # preview without actually copying
Key flags: -a archive mode, -v verbose, -z compress in transit, --delete mirror deletions
sftp jdoe@server01
sftp> get remote-file.txt
sftp> put local-file.txt
tmux new -s mysession
# detach: Ctrl+B then D
tmux attach -t mysession # reconnect later
tmux ls # list sessions
ssh -L 8080:localhost:80 jdoe@server01 # local port 8080 -> remote port 80
21. Package Management
►Installing, updating, and removing software — apt and dpkg for .deb packages, plus snap.
| Action | Command |
|---|---|
| Update package index | sudo apt update |
| Upgrade installed packages | sudo apt upgrade |
| Install a package | sudo apt install nginx |
| Remove a package | sudo apt remove nginx |
| Remove package + config | sudo apt purge nginx |
| Remove unused dependencies | sudo apt autoremove |
| Search for a package | apt search nginx |
| Show package details | apt show nginx |
| List installed packages | apt list --installed |
apt sits on top of — works directly with .deb package files.sudo dpkg -i package.deb # install a local .deb file
dpkg -l | grep nginx # is it installed?
dpkg -L nginx # list files a package installed
sudo dpkg --configure -a # fix a half-configured install
apt-cache policy nginx
sudo add-apt-repository ppa:some/ppa
sudo apt update
apt upgrade runs.sudo apt-mark hold linux-image-generic
sudo apt-mark unhold linux-image-generic
snap list
sudo snap install code --classic
sudo snap refresh
sudo snap remove code
22. Environment Variables
►Where environment variables come from, how to read and set them, and which startup files control them.
echo $PATH
export PATH="$PATH:/opt/mytool/bin" # add a directory for this session
printenv
printenv HOME
env VAR=value ./script.sh # set a variable for one command only
| File | Loaded when | Typical use |
|---|---|---|
~/.bashrc | Every new interactive non-login shell | Aliases, prompt, shell options |
~/.bash_profile / ~/.profile | Login shells | Environment variables, PATH |
/etc/environment | System-wide, all users, all shell types | System-wide PATH and locale defaults |
/etc/profile.d/*.sh | System-wide login shells | Vendor or package-installed environment setup |
~/.bashrc only take effect in new shells unless re-sourced.source ~/.bashrc
# or simply open a new terminal tab
export is lost when the terminal closes; add it to a startup file to make it permanent.echo 'export EDITOR=vim' >> ~/.bashrc
source ~/.bashrc
23. Date & Time
►Reading, formatting, and calculating with dates and times, plus controlling the system clock and timezone.
date [+FORMAT]
date
date +"%Y-%m-%d" # 2026-06-16
date +"%Y-%m-%d %H:%M:%S"
date +"%A, %d %B %Y" # Tuesday, 16 June 2026
Key flags: Common tokens: %Y year, %m month, %d day, %H hour (24h), %M minute, %S second, %A weekday name
date can calculate relative dates with -d, without needing a separate library.date -d "yesterday"
date -d "3 days ago"
date -d "next monday"
date -d "2026-01-01 +6 months"
timedatectl
sudo timedatectl set-timezone Europe/London
timedatectl list-timezones | grep London
cal
cal 2026
cal 6 2026
sleep 5 # 5 seconds
sleep 2m # 2 minutes
sleep 1h # 1 hour
time ./build.sh
24. Math & Numbers
►Doing arithmetic in the shell — bash's built-in integer math, bc for decimals, and number formatting.
$(( )), no external command required.echo $((5 + 3)) # 8
echo $((10 / 3)) # 3, integer division — bash has no native floats
echo $((10 % 3)) # 1, remainder
result=$((count * 2))
$(( )) but still seen in scripts.let count=count+1
result=$(expr 5 + 3)
echo "10 / 3" | bc -l # 3.33333333333333333333
echo "scale=2; 22/7" | bc -l # 3.14
printf "%05d\n" 42 # 00042
printf "%.2f\n" 3.14159 # 3.14
printf "%x\n" 255 # ff, hexadecimal
printf "%o\n" 8 # 10, octal
echo $RANDOM # random integer 0-32767
echo $((RANDOM % 6 + 1)) # dice roll, 1-6
shuf -i 1-50 -n 5 # 5 unique random numbers from 1-50
seq 1 10
seq 0 5 100 # 0, 5, 10... up to 100
for i in $(seq 1 3); do echo $i; done
25. Aliases & Shell Config
►Personalising the shell — shortcuts, prompt customisation, and behaviour tweaks, usually set once in dotfiles and forgotten about.
alias ll='ls -la'
alias gs='git status'
unalias ll
Key flags: Aliases set on the command line only last for the current session — add them to ~/.bashrc or ~/.bash_aliases to persist
~/.bashrc on Ubuntu's default setup.# ~/.bash_aliases
alias ll='ls -la'
alias update='sudo apt update && sudo apt upgrade -y'
alias ..='cd ..'
PS1='\u@\h:\w\$ ' # user@host:path$
# add to ~/.bashrc to make permanent
Key flags: Common tokens: \u username, \h hostname, \w full path, \W just the current directory name, \$ # for root, $ otherwise
shopt -s autocd # type a directory name alone to cd into it
shopt -s histappend # append to history file instead of overwriting
shopt -s globstar # enables ** for recursive globbing
export HISTSIZE=10000 # commands kept in memory per session
export HISTFILESIZE=20000 # commands kept on disk in ~/.bash_history
export HISTCONTROL=ignoredups # don't store immediate duplicate commands