Part III covered moving around and working with files. This one picks up where that left off — who can touch a file, what's actually running on the machine, how much space things are taking up, and how to reach another machine over the network.
chmod — change permissions
Every file has read, write, and execute permissions for three groups: the owner, the group, and everyone else.
ls -l script.sh
-rw-r--r-- 1 user user 128 Aug 28 10:00 script.sh
That rw-r--r-- breaks into three chunks of three: owner (read/write), group (read only), others (read only). To make it executable for the owner:
chmod u+x script.sh
ls -l script.sh
-rwxr--r-- 1 user user 128 Aug 28 10:00 script.sh
You'll also see the numeric form — chmod 755 script.sh — where each digit is a sum of read(4)+write(2)+execute(1) for owner, group, others respectively. 755 means owner gets all three, group and others get read+execute only.
chown — change ownership
sudo chown user:user script.sh
Sets both the owning user and group in one shot (user:group). You'll mostly need this after copying files in as root, or fixing permissions on something pulled from a shared drive — files that technically belong to someone else on the system.
grep — search inside text
grep "error" server.log
[2026-08-28 09:14:02] ERROR: connection refused
[2026-08-28 09:22:41] ERROR: timeout waiting for response
Prints every line containing the search term. Add -i to ignore case, -r to search recursively through every file in a folder, and -n to show line numbers alongside each match:
grep -rn "TODO" ~/projects/myapp
src/main.py:42:# TODO: handle empty input
src/utils.py:15:# TODO: this is a hack
ps — see what's running
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
user 1 0.0 0.1 22528 3200 ? Ss 09:00 0:01 /sbin/init
user 842 0.1 0.4 412300 32100 ? Sl 09:02 0:03 gnome-shell
user 1190 2.3 1.8 891200 148000 ? Sl 09:15 1:42 firefox
a shows processes from all users, u gives the detailed columns (CPU%, memory%, command), x includes processes not attached to a terminal. The PID column — process ID — is what you'll need for the next command.
top — watch it live
top
Same idea as ps but refreshes continuously, sorted by CPU usage by default. Press q to quit. If you have it installed, htop is the friendlier, color-coded version of the same thing — worth installing if it's not already there.
kill — stop a process
kill 1190
Sends a termination signal to the process with that PID (grab it from ps or top). If it doesn't respond — some processes ignore the polite request — force it:
kill -9 1190
-9 is SIGKILL, which the process can't ignore or clean up after. Use it as a last resort; a plain kill gives the process a chance to save its state and exit properly first.
df — disk space, by filesystem
df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 70G 42G 25G 63% /
/dev/sda4 74G 61G 9.5G 87% /media/storage1
-h means "human-readable" — GB and MB instead of raw byte counts. This is the first thing to check when something complains the disk is full.
du — disk usage, by folder
du -sh ~/Downloads
4.2G /home/user/Downloads
-s summarizes into one total instead of listing every file inside; -h again means human-readable. Where df tells you a drive is full, du tells you which folder is actually eating the space — run it on a few candidate folders to narrow it down.
tar — archive and compress
tar -czvf backup.tar.gz project/
c creates an archive, z compresses it with gzip, v prints each file as it's added (verbose), f names the output file. To reverse it:
tar -xzvf backup.tar.gz
x extracts instead of creating. The zvf part stays the same either direction — it's really just c vs x that flips.
curl — talk to a URL
curl -O https://example.com/file.zip
-O saves the file under its original name instead of dumping its contents to the terminal. Also useful for quickly checking what an API endpoint returns, without opening a browser:
curl https://api.example.com/status
ssh — log into another machine
ssh user@192.168.1.20
Opens a remote shell on that machine, prompting for a password (or using your SSH key if one's set up). Once connected, everything you type runs on the remote machine, not your own, until you exit.
scp — copy files over SSH
scp report.pdf user@192.168.1.20:~/Documents/
Same permission model as ssh, just moving a file instead of opening a shell. Reverse the order to pull a file from the remote machine instead:
scp user@192.168.1.20:~/Documents/report.pdf .
The trailing . means "save it here, in my current folder."
alias — shortcuts for long commands
alias ll='ls -la'
ll
drwxr-xr-x 12 user user 4096 Aug 16 01:29 .
drwxr-xr-x 3 root root 4096 Sep 28 2025 ..
drwxr-xr-x 4 user user 4096 Aug 21 21:44 Desktop
Lasts only for the current terminal session unless you add it to ~/.bashrc — do that once and it's there permanently, every time you open a new terminal.
history — what did I just type
history | tail -n 5
501 cd ~/projects
502 git status
503 git add .
504 git commit -m "fix bug"
505 history
Every command gets a number. Re-run any of them with ! followed by that number — !502 re-runs git status — faster than retyping or scrolling back through terminal output.
ln — create a link
ln -s ~/projects/config.yaml ~/config.yaml
-s makes a symbolic link — a pointer to the original file, shown with an arrow in ls -l:
ls -l ~/config.yaml
lrwxrwxrwx 1 user user 32 Aug 28 10:05 config.yaml -> /home/user/projects/config.yaml
Edit the link, and you're actually editing the original file — useful for keeping one real copy of a config while making it accessible from several places at once, without duplicating it.
Between this and Part III, that's 30 commands — enough to navigate a machine, manage files and permissions, keep an eye on what's running, and reach another machine over the network. Everything past this point tends to be command-specific rather than foundational, and worth looking up as it comes up rather than memorizing in advance.