Sunday, July 22, 2018

Keeping the Bash shell history

There are a lot howto's and instructions about keeping the shell's history but my favorite is my own fork of dhist.sh which is sdb. Now you're probably asking as to why would anyone wants to keep the history of all the commands you have written during the interactive shell? Well for starters you can check which commands did you executed during the last week on which directory or the exit status of that command. or you want to check for the commands that has a word  foo  somewhere in there or you remember a very cool command that has a lot of combinations of pipes, subshell, redirections and so on, that you have had executed but forgot the exact syntax.



 The history is kept in a file called .bash_history inside your $HOME directory. A normal text file has its limitations because of the file size. Imagine even if you manage to save all the history in one file then that file could get bigger and bigger depending on how much data in contains.

In openSUSE Leap 15.0 syslog can be used to log bash history according to this
site which actually works as expected/advertised, unfortunately sdb can't be used 
in parallel with that set up. Just don't edit the /etc/bash.bashrc file instead create a
new file named /etc/bash.bashrc.local .

Any how sdb saves the history in a sqlite3 database, why sqlite? because it has no server client authentication. If you have read and write to the database file then you can use that database there is no admin privilege involve. Quoting what google has to say about sqlite

Unlike other databases (like SQL Server and MySQL) SQLite does not support stored procedures. SQLite is file-based, unlike other databases, like SQL Server and MySQL which are server-based. SQL is a Structured Query Language used to query a Database usually Relational Database Systems.

Sqlite is being used by some of the popular web browsers like firefox and most modern smart phone also like Android. Yes there is always a risk of sql-injection  which can either collect user info or destroy the database and worsts it can blocked everybody in the entire system but since sqlite is only a file based then the risk is minimal. No authentication on the server, client side needed. The worst that could happen is you lose your history table from the database. At the point the "Always keep a backup" comes in.

For those of you who does not know how to use vim  you should at least know howto exit or quit vim without editing a file. Since vim is the default  value of the environment variable EDITOR if it is empty. Press the escape key and then key in the colon and the q key followed by an exclamation key.

   <esc>:q!   

Create a cron job to automatically save the database at some safe place. An example on howto do it in openSUSE every hour.

   0 * * * * /usr/bin/sqlite3 database ".backup /path/to/new/safe/location/database"   

Give the absolute path of the sqlite3 executable and replace the database with the correct name and path and the path to the new database  file. Note that the database will be over ridden every hour so it is wise to create a script and just use cron to execute it

Now lets see how we can use sdb in the interactive shell.

Let's say you want to look for commands in the current session e.g. currently open terminal
that you're using. Type

  sdb   

If you just open a new terminal then the only thing you will see are the headers. Which
looks like this (with the -c option).

+-------------+-----------+--------------------+----------------------+-------------+-----------+-----------------+------------------+
 |     ID         |  COUNT |    DATE/TIME   |    USER@HOST   | STATUS   |    TTY     | DIRECTORY |▶ COMMAND |
+-------------+-----------+--------------------+----------------------+-------------+-----------+-----------------+------------------+

Now if you want to see the other shell sessions and current ones. e.g. if there are other terminals that are open and you or others that is using sdb. Use the -a option, which defaults to 100 lines only.

   sdb -a   

If you want to see all the commands starting from the very beginning add the -m option and use the + sign to specify the maximum value instead of typing 999999999999999999 for the value of -m. Yes they are 18 9's!

  sdb -am+  

Change the + sign into some number/digit to specify how much lines you want.

If you want to see the directory, exit status, user and host, then add the -c option.

   sdb -cam+  

The -u, -h, -l and -d can be specified for specific query as well.

If you want to see sqlite commands that has been executed then add the -v option.

   sdb -vcam+   

To check for commands that starts with zypper use the -b option

   sdb -vcam+ -b zypper   

To check the commands that starts with zypper and ends with bash add the -e option.

   sdb +vcam+ -b zypper -e bash  

On the other hand the -w option can do that also

    sdb +vcam+ -w 'zypper%bash'   

The % is like the glob in the shell which is * , but the % is for sqlite.

To check for commands that was executed from 10 days ago and now.

   sdb -cam+ -t '-10 days, now'   

To check the commands that was executed in the directory /foo and all the directory under it
recursive search.

    sdb -vcam+ -r /foo   

It is also possible to re execute the commands that you can find in the query by providing
the ID of the command. Run command with the id 100

  sdb -E 100  

Now some example of long combination of options.

    sdb -am+ -n0 -w 'zypper%bash' -u jetchisel -h leap150 -r "$HOME" -t '-1 year, -2 days'    


The -a for all commands from the other sessions and current ones. (100 lines only.)
The -m+ for all the commands from the beginning.
 First the  -n option with the zero argument checks for the commands that exited with a zero status.
The -w for commands that starts with zypper and ends with bash.
The -u for the username of the user
The -h for the hostname  of the computer.
The -r for a recursive search for commands on and under the directory "$HOME"
The -t is for searching commands starting from last year until 2 days ago.

Enjoy folks....

1 comment: