CentOS ships with "yum", which is the default package manager for RHEL based systems. Like other package managers for distros such as Ubuntu, it allows you to easily add, remove, and update software on your Linux distro. It also takes care of dependencies. So for example, if you install package "A" that requires "B" and "C" to function, yum will automatically install "B" and "C" for you without you needing to worry about doing so manually.
This works great - except for one problem. Yum doesn't really make a distinction between packages that were installed manually and those that were installed automatically as dependencies. This can lead to problems when you're trying to see what you installed on your system manually. In an OS like Windows, the "Add/Remove Programs" shows you what you've installed. Yum has no similar feature. It's important because if you're setting up a new server, you might want to know what packages to install manually in order to replicate your current system.
Let's look at how we can fix this.
The Problem with the "yum history" Command
The most common way to check what you've installed with yum is to run the following command:
This shows you the most recent commands you've issued with yum as shown here:
Unfortunately, this has two problems:
- It's a very limited list. Just the past 20 commands;
- It shows ALL commands - not just install/remove.
So using "yum history" to get a broad overview of the software that you've manually installed on your system is very inefficient.
Getting yum Info Directly from the Database
Yum stores its interactions in an sqlite database that we can query using the built-in "sqlite3" command (for CentOS 7). To get the name of this database, list the contents of /var/lib/yum/history like this:
ls -1a /var/lib/yum/history
This will give you the name of the ".sqlite" file like this:
Make a note of your database name and then use it in the following command:
sqlite3 /var/lib/yum/history/history-2016-10-25.sqlite "select tid, cmdline from trans_cmdline WHERE cmdline LIKE '%install%'"
Replace the file name in bold above with your own sqlite database file name. This generates the following output on the terminal:
This is the output of every "install" command run on your system right from the beginning. It's more useful than "yum history" because it shows you the complete history instead of 20, and also shows you only the "install" lines. If you're familiar with SQL syntax, you can modify the command above to get even more useful information.
However, this is still insufficient for our needs. The biggest problem is that we don't know which packages have been removed! Of course, we can change the command to show the "remove" commands as well, like this:
sqlite3 /var/lib/yum/history/history-2016-10-25.sqlite "select tid, cmdline from trans_cmdline WHERE cmdline LIKE '%remove%'"
Then we have to cross reference this list with the first one to see which packages were removed, and which ones are still on the system. All in all, a pretty incomplete solution!
Using the yumdb Command
Another tool called "yumdb" is used to get more info from yum using "key/value" pairs. Yumdb is installed as part of the "yum-utils" package. So install it using this command line:
yum install yum-utils
Now the following command will show us the original yum command for every currently installed package on the system:
yumdb search command_line install*
Here's a sample output:
For example, we can see that "yum install httpd" was responsible for the two packages marked in the red box. This is useful, because we now only need to compile a list of unique "install commands" to account for every single package on our system! So far, this solution comes closest to what we want - a complete list of manually installed packages on CentOS.
But there is a final - and more permanent solution.
Replacing yum With its Successor - dnf
DNF is the evolution of the "yum" package manager and is already being used on Fedora systems since November 2015. The current evolution of CentOS version 7 dates back to June 2014. So the next iteration of CentOS will most likely use "dnf" instead of "yum". I won't go into the differences of why dnf is better than yum, but it's good to know that you're using a tool that's going to replace yum anyway.
dnf is already available in the EPEL libraries, and we can install them using the following two commands:
yum install epel-release yum install dnf
The entire question of which packages are manually installed on Linux can be solved with as simple dnf query. The catch is that all the software has to be installed using dnf in the first place! So if you've already installed packages using yum, then dnf won't help you. But now's a good time to replace yum with dnf. So let's say we install a package with a lot of dependencies using dnf.
dnf install links
"Links" is a command line based browser and the installation requires a ton of dependencies:
After installation with dnf, we just run the following command:
dnf history userinstalled
And we magically get all the user installed packages that were added manually to the system without any dependencies:
This is exactly what we're looking for, and dnf provides it. All the manipulations of yum can be avoided by using dnf as a replacement - a replacement that is going to happen anyway. So if you're reading this and want a permanent solution for the future, now's a good time to make the switch to dnf for yum! You'll have an easier time getting an overview of manually installed packages this way.