The other day, I ran into the age-old situation where a Python package failed to
build because the
Python.h header file was missing. This happens a lot, so I
hardly think about it anymore, but it used to be a big problem.
What is this file? Where did it come from? Who is providing it? Who should be providing it? The easiest solution is to paste the error into StackOverflow, but before you do that, try these steps first to save some time and learn about your system's layout in the process.
Sometimes, the easiest way to search for something is to have an idea where it might be in the first place. This happens when, for example, the thing you're looking for is in a standard location.
It turns out that standards are (mostly) a thing in Linux, and this is why the Filesystem Hierarchy Standard is important. It lets you know where something should be so you can start your search and end it quickly. Some examples:
If it's the kernel, it's probably in
If it's a system library, it's probably in something like
If it's a system config file, it's probably in
If it's a user config file, it's probably in
If it's a file you created, it's probably somewhere in your home directory.
If it's a log file, it's probably in
If it's a temporary file downloaded from the internet, it's probably in
Using these rules of thumb, and having an understanding of your filesystem
layout, is probably the fastest way to find the things you're looking for. Do a
ls in the right directory and find what you need.
However, we'll soon see that this doesn't work for everything.
Sometimes there's a command on your system—one of your favorites that you use
all the time—and you just want to where it's installed. Or maybe you've done
something strange to your system PATH and want to find out what directory the
tool is being sourced from. Either way, the quickest way to find this info is
$ which python3 /usr/bin/python3
Note that the
which command may not be available on every platform, so when
it's not, the less-convenient but still very usable
type command can be used
$ type python3 python3 is /usr/bin/python3
This is where the
find command really shines. It does an awful lot more than
what we're using it for here, but it is also an ideal and simple tool for
everyday filesystem searching.
Here's the basic incantation:
find PATH [-name PATTERN]
To find all files in the current working directory (denoted by
To find every file on the system named
find / -name Python.h
To find every file with Python in the filename under the directory
find /usr/share/ -name \*Python\*
To find every file on your system with the
.h extension that's not a directory
or other special file type (commonly known as a regular
find / -name \*.h -type f
When you've been using a system for awhile, you start to get a feel for the likely origins of certain files.
For example, you may have noticed that executables tend to live in
and resource files in
/usr/share/; this is fairly common because the system
package manager by default puts those files in those respective directories.
You may have also noticed that custom installations live in
/opt/. In many cases with Linux, the local sysadmin is probably you yourself,
so unless you did otherwise, custom installations have a high likelihood of
being found in those places. For everything else, it was probably installed by
the package manager.
So if you think a file should exist, and it doesn't, the local package manager is a good place to start looking for it.
dpkg -S is an excellent tool for apt-based systems to find what you need:
dpkg -S FILE
Python.h cannot be found, you can quickly determine if it's present on
the system by doing the following:
dpkg -S Python.h
In some situations, the returned results will be too long, so you can use a
grep to narrow the results:
dpkg -S ldd | grep ldd$
RHELish systems have
rpm -qf to determine what package a file came from:
rpm -qf FILE
However, as it requires a full path, you'd need to run
find anyway to get that
information before this command is useful:
rpm -qf $(find / -name Python.h)
Here it is in action:
$ find / -name Python.h /usr/include/python3.11/Python.h $ rpm -qf $(find / -name Python.h) python3-devel-3.11.1-1.fc37.x86_64
It could be that the file you're looking for hasn't been installed yet, but you are confident that it can be installed via your local package manager. This is encountered frequently when you're first installing a system or when you're trying to package a container.
Luckily, package managers generally have tools that allow you to search their package contents directly.
For Debian-based systems,
apt-file is available. Annoyingly though, not only
is it not installed by default, but you also need to build its index before
you can use it. Oh, well. A temporary pain:
sudo apt-get install apt-file sudo apt-file update
But now you'll be in
apt-file find FILE
Let's find our Python development header:
apt-file find Python.h
You'll end up with a lot of results, so adding some targeted
would be useful:
apt-file find Python.h | grep '/Python.h$' | grep python3
$ apt-file find Python.h | grep '/Python.h$' | grep python3 libpython3.10-dbg: /usr/include/python3.10d/Python.h libpython3.10-dev: /usr/include/python3.10/Python.h libpython3.11-dbg: /usr/include/python3.11d/Python.h libpython3.11-dev: /usr/include/python3.11/Python.h
Now you know where it should be installed, even though you haven't installed it!
For RHELish systems,
dnf has the
dnf provides FILE
rpm -qf, it wants a full path (ugh), but unlike
dnf provides has a wildcard escape hatch so that you can get on with your life.
Here's how we can search for our
dnf provides '*/Python.h'
grep would have been useful, but the output of this command does not lend
itself to parsing very easily:
python3.6-3.6.15-12.fc37.i686 : Version 3.6 of the Python interpreter Repo : fedora Matched from: Filename : /usr/include/python3.6m/Python.h
Piping the output to
less is more convenient here:
dnf provides '*/Python.h' | less
This will open the output in a pager and allow you to search through it by pressing forward slash (/) and typing a search query.
If you're not sure where to look for something, chances are, you also don't know what you are looking for. This is probably the right time to go on StackOverflow, or better yet, ask a trusted friend.
Knowing what you seek is the first step to finding it. 🤯