Chapter 5
Where software comes from
On Windows you download a program and double-click it. Linux does something different, and better. This chapter explains how software arrives, where it lands, and how the shell then finds it.
A package is a program plus its paperwork
Software on Ubuntu comes in packages. A package is one file that holds:
- the program itself
- where each of its files should go
- a list of other packages it needs in order to work
- a version number
That third item matters most. Almost no program stands alone. It needs libraries, which are lumps of code shared between many programs. The package says what it needs, so the system can fetch those too.
In step 3 you asked for
clang, and a long list of other names went past. Those were
its dependencies — the pieces clang cannot work without. You did not have
to know their names. The package did.
Packages live in a shop
Ubuntu keeps its packages on servers called repositories. Think of a repository as a shop with a catalogue: tens of thousands of programs, all built and tested to work together.
Your machine holds a copy of the catalogue, not the shop. This explains a command you have run without thinking:
| Command | What it does |
|---|---|
apt-get update |
Fetch a fresh catalogue. Downloads no programs at all. |
apt-get install nano |
Look in the catalogue, fetch nano and whatever it needs, and put it in place. |
update before install is a habit worth keeping. An
old catalogue points at versions the shop has already replaced, and the
install fails for a reason that looks like nonsense.
Why you have to type sudo
A program installed this way goes into a system folder such as
/usr/bin. Those folders do not belong to you. They belong to an
account called root, which is allowed to change anything.
sudo means: run this one command as root. It asks for
your password to check that it is really you sitting there.
This is a safety feature, not an obstacle. Because your normal account cannot write to system folders, a mistake you make — or a bad program you run by accident — can only damage your own files, not the whole machine.
If a command needs sudo, it is about to change the machine
for everybody. If it does not, it only touches your own files. That is a
good moment to read the line once more before pressing Enter.
How Ubuntu knows a package is genuine
Packages arrive over the internet. Something must check that they came from who they claim, and were not changed on the way.
Each repository signs its catalogue with a key. Your machine keeps the matching key and checks every download against it. If the check fails, the install stops.
This is what step 5 is doing when it adds a key before installing Java. The JDK comes from Adoptium, not from Ubuntu, so your machine has to be told that Adoptium can be trusted — once, on purpose, in the open.
Where the program ends up
Programs from packages nearly always land in one place:
$ which python3
/usr/bin/python3
As chapter 1 showed, that is simply a file. The package put it there, and
sudo is why it was allowed to.
PATH is the shell's list of places to look
You type python3, not /usr/bin/python3. So how does
the shell find it?
It keeps a list of folders to search, in order. The list is called PATH. When you type a name, the shell walks the list, folder by folder, and runs the first match it finds.
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/games
The colons separate the folders. Read it as a list:
- look in
/usr/local/bin - then
/usr/bin - then
/bin - then
/usr/games - if it is in none of them, give up
./hello makes complete sense
The folder you are standing in is not on that list. So
typing hello makes the shell search four folders, none of
which hold your new program, and report command not found.
./hello is not a name to search for. It is a path. It tells
the shell to skip the list and look exactly here.
A folder of your own
Not every program needs sudo. Some are installed just for you,
into a folder inside your home:
~/.local/bin
That is where uv goes in step
8, and where bat and fd get their proper names
in step 6. No sudo
needed, because it is your own folder.
But it only works if that folder is on your PATH. On a fresh Ubuntu it often is not, which is why several of the setup scripts add it.
.bashrc runs every time you open a terminal
PATH is not carved in stone. It is set up fresh for every shell you start.
The shell builds it by reading a settings file in your home folder called
.bashrc — hidden, because its name starts with a dot.
When a script adds a line like this to .bashrc:
export PATH="$HOME/.local/bin:$PATH"
it is saying: from now on, look in my own folder first, then everywhere you were already looking.
A script edits .bashrc and finishes. You type the new command
and get command not found. Nothing is broken.
Your shell read .bashrc when it started, minutes ago. It has
not read it again. The new line is in the file but not in this shell.
Two ways to fix it. Read the file into the shell you are in:
$ source ~/.bashrc
Or simply close the terminal and open a new one, which reads it anyway.
What "command not found" really means
It almost never means the program is missing. It means one of these:
- the program is not installed
- it is installed, but in a folder that is not on your PATH
- it is on your PATH, but this shell has not reloaded
.bashrcyet - you spelled it wrongly
Work through them in that order and you will find it every time.
Not everything comes from apt
Two steps deliberately go outside the shop, and it is worth knowing why.
| Tool | Where it comes from | Why |
|---|---|---|
uv |
its own installer script | It is new and moves quickly. Ubuntu's catalogue would always be behind. |
gradle |
downloaded from Gradle | Ubuntu's version is usually several years old. |
The trade is simple. From the shop you get checking, dependency handling and tidy removal, but sometimes an older version. From outside you get today's version, and you take responsibility for trusting the source yourself.
Try it
See your search list:
$ echo $PATH
Find which folder a program came from:
$ which bash
Ask the catalogue about a package, without installing anything:
$ apt-cache policy bash
Count how many packages are already installed on your machine:
$ dpkg --get-selections | wc -l
Look at the lines the setup scripts added to your settings file:
$ grep system_setup ~/.bashrc
You can now explain
- What a package holds, and what a dependency is
- Why
apt-get updatedownloads no programs - What
sudodoes, and why not needing it is a good sign - Why a new repository has to add a key first
- What PATH is, and how the shell uses it
- Why
./hellois needed for a program you just built - Why
.bashrchas to be reloaded before a new command appears - The four reasons for command not found
