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.