TIL: Why there is /bin and /usr/bin, /lib and /usr/lib, etc on Unix systems

If you’ve ever navigated around a Unix system you may have wondered why there are /bin and usr/bin directories or /lib and /usr/lib or /sbin and /usr/sbin – or like me, you just took it for something that probably has any meaning but isn’t relevant enough to look into.

Well, today it became relevant: When upgrading a Docker image from Debian 11 to 12 I encountered a lot of issues with a utility called “usrmerge“, and this sent me down a rabbit hole.

As with most things in the Unix world it started with someone doing a thing for reasons of technical limitation.

You know how Ken Thompson and Dennis Ritchie created Unix on a PDP-7 in 1969? Well around 1971 they upgraded to a PDP-11 with a pair of RK05 disk packs (1.5 megabytes each) for storage. When the operating system grew too big to fit on the first RK05 disk pack (their root filesystem) they let it leak into the second one, which is where all the user home directories lived (which is why the mount was called /usr).

Rob Landley, via http://lists.busybox.net/pipermail/busybox/2010-December/074114.html

So /usr/ existed because the Operating System no longer fit on the first disk, so “some parts but nut all” of the OS were split to the mounted second disk – reasonable.

The quote continues: “[…] They replicated all the OS directories under there (/bin, /sbin, /lib, /tmp…) and wrote files to those new directories because their original disk was out of space.” – later on, they made a new /home directory where all the user specific stuff lived and /usr and /bin could both be used for the OS.

Well, … the split between /bin and /usr/bin has never been reverted or “fixed”, which is why a thing from the 1970s still exists in modern-day Unix systems (Debian, Ubuntu, and MacOS all have these two directories)!

Enter today, 28th November 2023, where I try and upgrade a Debian 11 based image in a Docker build and what breaks my build? A tool called usrmerge, which is supposed to fix this /bin vs. /usr/bin nonsense for Debian 12 and onward.The solution is – basically – to merge everything from /bin into /usr/bin, then symlink /bin/ to /usr/bin (and the same for /lib and /sbin).

I ended up not upgrading the Debian 11 image to Debian 12, instead I enabled bullseye-backports to update the software inside the Docker image – but that’s a story for another day.

Additional reading


Leave a Reply