Kir: find commands by describing them from the shell
When doing system administration to fix a crash on some Unix-based server, I have run several times into the issue of trying to remember how to perform a certain task, but not remembering the exact sequence of commands. After that, I am always doing the same thing, and I have to resort to do a search on Google to find the commands I need. Those tasks are generally not frequent enough to be worth it to memorize the commands or create a script, but frequent enough for the process of searching to become really annoying. It’s also a productivity issue since it requires me to stop the current workflow, open a web browser and perform a search. For me, those things include tasks such as “how to find the number of processors on a machine” or “how to dump a Postgresql table in CSV format.”
I thought that it would be great to have some piece of code to just be able to query Google from the command-line. But that would be a mess, as for each query I would need a simple sequence of commands that I need to type, and not a blog article with fluffy text all around which is what Google is likely to return. Also, I thought about using the API of commandlinefu.com to get results directly from there. So I did a small Python script that performs text search that way, but the results were never exactly what I was looking for, since the commands presented there have been formatted by people who do not have the exact same needs I have. This is what brought me to implement Kir, a tiny utility to allow for text-search directly from the command-line and give the exact list of commands needed.
How does Kir work?
For instance, I never quite remember how to get the version of Ubuntu installed on a system. Possible commands for that are:
cat /proc/version, and
cat /etc/issue. So here is what I do:
- Identify that I am looking for the same set of commands over and over again. Here it’s looking for a way to get the version of Ubuntu.
- Find the commands I need to type in. Here,
cat /proc/version, or
- Define which keywords I am likely to use when I will look for this information in the future. In that case, I think that the following keywords define the problem quite well: distribution, linux, version, distro, ubuntu.
- Add all this information to the Kir configuration file, in
rule: distribution, linux, version, distro, ubuntu lsb_release -cs cat /proc/version cat /etc/issue
The first line tells Kir that a new “rule” is starting, with the keywords “distribution, linux, version, distro, ubuntu”. The following lines are the information that I was to be able to read whenever I am looking for those keywords. So now when I type:
$ kir linux version
3 results found Best result: *** 3: distribution version distro ubuntu linux ---------------------------------------------------------------- lsb_release -cs cat /proc/version cat /etc/issue **************************************************************** Other results: ---------------------------------------------------------------- *** 4: info version package linux dependencies ubuntu *** 12: svn version old previous
The best matching result is displayed first, with its full corresponding text. Then, other possible results are displayed, based on what I have put in my .kirrc file. Each result line starts with a number for the entries, here the numbers are 3, 4 and 12. If I want to get an item with its number, for instance #4, I can do it with:
$ kir 4
and I am getting this:
sudo apt-cache showpkg package-name
Note: this is because I added a rule that gives me, for Ubuntu, the command to the list of packages a specific package depends on.
Installing Kir on your machine
Installing Kir is extremely simple, as it’s just a tiny Python script. Note that since Kir is using sqlite3 for text search, you will need Python 2.5 or above. The steps are as follow:
- Get all the files from the Github repository: https://github.com/goossaert/kir
- Rename the kirrc-example file to .kirrc and put it in your home directory
- Create an alias for the kir command in your ~/.bashrc or ~/.profile file, like that :
alias kir="python /path/to/kir.py". Or you can call this alias whatever you want instead of “kir”.
- Change the variable PATH_CONFIG in your kir.py file to point to the path of your .kirrc file. To make sure kir.py finds the file, use an absolute path, and not the
~character to refer to the home director.
- Now you can start creating your .kirrc file, below is an example. You can also include notes about some tasks that you are often doing (here there is a rule with IP addresses of some servers, and a not to remember to restart to other servers after performing a specific task).
- In the .kirrc configuration file, the text referring to a rule will be all what’s below the rule and before the next rule. Empty lines will be skipped. the
#character can be used to comment lines, and that
Example of .kirrc file:
rule: distribution, linux, version, distro, ubuntu lsb_release -cs cat /proc/version cat /etc/issue # this rule is for the task of setting up new nodes rule: server, ip, address, hosts, hostnames production: prod4 integration: integration2 dns server: 184.108.40.206 and remember to restart all nodes after changing the parameters rule: dependencies, linux, package, info, ubuntu, version sudo apt-cache showpkg package-name # better than using wget rule: download, resume, scp, partial, get, wget rsync -vrPt -e ssh host:/remote_path/* /local_path/
Note that you can use Kir to store any kind of information that you may need in while you are using your shell. This doesn’t have to be a sequence of commands. For instance in the file above, I have a rule that contains the hostnames of some servers, along with a note at the very end (remember to restart the servers). These could be the hostnames of servers that you often use for a specific task, and don’t want to have to remember.
With Python 2.4 or below
You will need to install a replacement for sqlite3, like PySqlite. You can find this package here: http://trac.edgewall.org/wiki/PySqlite. Then, replace the line
import sqlite3 in kir.py by
from pysqlite2 import dbapi2 as sqlite3, all you’re all set!