Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I programmatically access the bash command history in C?

Tags:

c

bash

I hate the bash 'history' command. It never finds the history items I want. Sometimes I can get what I want with 'history | grep XXX' but often either the history is too long (400+ hits! yay) or too short (no hits. Boo).

I thought to myself, why dont I write a little 'history helper' command that lets me basically 'star' specific history items and make them always turn up in my history, with both a global star list and a cwd specific star list.

Sounds amazing. So I naively tried to read the history by doing this:

system("history > blah")
FILE *fp = fopen("blah", "r")

Oh, that didn't work. Ah, I get it, the system() command runs in it's own context and can't access the bash history. Drats. Ok, so I'll try reading ~/.bash_history

ba baaa~ Nope. That's only got the history up until the last call to either a) history -w, or b) call to exit from the shell.

So, question: How can I programatically access the current bash history in C?

(NB. No, not what's in ~/.bash_history, the current history, the exact output you see when you type 'history' from the prompt; also, why C you ask? why not...but really, because I already have a handy ncurses wrapper I was going to use to let me get fancy auto-completion and sub-selection history searching on normal terminals...)

Edit: Please, if you have something useful to contribute, I'm happy to hear it, but I get a little sick of comments like 'you should read the bash history man pages'.

I have read them. There is nothing that allows me to 'star' a history item and have it always turn up in my history, and nothing that allows me to maintain a per-directory history context. These are things that history does not support. I appreciate this. That's why I want to write a helper function, for my specific purpose. If you have a comment like "maybe you should read the history man pages some more", please just hold it in, and don't respond; it doesn't really address my question. :)

like image 383
Doug Avatar asked Oct 06 '22 22:10

Doug


2 Answers

Short answer

You can find the answer into history source which is bash builtin.

Long answer

Looks like you just need to read help history and man bash a while.

Your history file is constantly rewriting with shell (depending on your settings. by default it is done at the logout/exit moment). You need to hack the shell to add specific rules to do that. However you're pretty far from this level.

just because if you were pretty close to it, you didn't ask how to operate with .bash_history from c =)

However there is another way to improve your history: increase your history size, restrict duplicate reading and make all your command was getting into history immediately after executing. For that you need put into your .bashrc following variables:

PROMPT_COMMAND='history -a;history -n'

export HISTCONTROL=ignoredups
export HISTTIMEFORMAT='%F %T '
export HISTSIZE=100500

shopt -s histappend
shopt -s cmdhist

Also you can prevent specific commands recording with

export HISTIGNORE="unwanted_command:unwanted_mask*"

Hope it will help you.

like image 67
rush Avatar answered Oct 13 '22 09:10

rush


Working-Directory-Specific History

function cd {
    builtin cd "$@"
    if [ -f .cwdhist ]; then
        history -r .cwdhist
    fi
}

Starred History Commands

The basic principle is to combine some shell function logic to write and read history around your history helper program.

function histedit {
    history -a
    historyhelper $HOME/.bash_history $HOME/.histout
    history -c
    history -r $HOME/.histout
}

The history -a command appends all recent history to the history file. Then the function invokes your history helper. You can put whatever smarts you want into this program, ensuring that your favorite commands are in the history, and adding them if they aren't, then leaving its output in .histout (or whatever). Then the function continues, clears, and reloads history. Maybe it should avoid clearing history. Or maybe the function should abort if historyhelper returns a nonzero exit status. All kinds of stuff you can do here.

like image 41
Stuart Marks Avatar answered Oct 13 '22 11:10

Stuart Marks