5

Duplicates are already turned off, but that's not enough (I feel like I have to enter commands too often).

Assume I have a capacity of 2000 entries of by bash history and a command which I used very often (n times) in the past but not recently and I want to use again now. Assume this command is at the oldest position in the history and would be evicted after the next non-duplicate command execution. I would like this command to be preserved and the oldest command (with usage count < n) to be evicted from history instead.

One might argue that this makes the bash history not a (linear) history anymore. I agree, but don't care since I want easy access to my favorite commands (being automatically collected).

I'm using bash 4.3.42 on Ubuntu 15.10.

2
  • Not something that can be easily done without modifying the source code to Bash.
    – fpmurphy
    Commented Nov 28, 2015 at 9:41
  • Yes i have the same issue so i always copy this command manually to a text file and then using cat filename copy command and paste it. I do it manually so if you find a solution please let us to know
    – makgun
    Commented Nov 28, 2015 at 21:39

2 Answers 2

4

Warning: This is not an answer to the question as it stands, but rather a suggestion for an approach that you may find useful.

I feel your pain. I like to keep around my Bash history as well, and be able to recall commands that I might have run a long time ago. I have developed an approach that allows me to keep all of my Bash history within a reasonable history size.

  1. my Bash history settings are:

    HISTCONTROL=ignoreboth:erasedups
    HISTIGNORE="?:??:???:$HISTIGNORE"
    

    That helps to keep down the entries that end up in the Bash history in the first place. Commands like ls are shorter to type than to recall, so there's no point in storing them (that's what HISTIGNORE is for). ignoreboth is shorthand for ignorespace and ignoredups. The former prevents entries with a leading space from ending up in the history. I use it for commands that I know I will never recall, or never want to recall, like rm -rf * :). There's plenty more stuff that I ignore by default (not shown), which keeps the history size down.

  2. Despite the countermeasures above, duplicates still end up in my history (e.g., due to multiple Bash shells open at the same time). I have a counter in my prompt that shows me the current history size

    PS1='\u@\h:\w:\!> '
    

    (The relevant code is \!, a.k.a. history number of this command.) That shows me when it is time to 'clean up' (see next step).

  3. I periodically 'clean up' my Bash history by running the following command:

    tac ~/.bash_history | awk '!seen[$0]++' | tac > ~/.bash_history.new && mv ~/.bash_history.new ~/.bash_history
    

(presuming your Bash history is stored in ~/.bash_history of course). This command removes duplicates while respecting order: commands used last remain last. Only the last (most recent) duplicate is retained.

With this approach, I've been able to keep all of my Bash history within a very modest history size of 600 to 1000 entries.

2
  • I asked meta.stackoverflow.com/questions/332134/… for how to get the leading space in the rm -rf * element, just out of curiosity. Commented Aug 10, 2016 at 20:40
  • @KarlRichter that's useful to know and there are occasions when it can be put to good use indeed ;-) thanks for looking this up!
    – Edward
    Commented Aug 14, 2016 at 9:52
0

Another answer that doesn't answer this exact question but may give a viable solution to the root problem:

I have a couple of settings/scripts triggered from my .bashrc/.bash_profile that I use to capture any command I ever enter into any terminal, and then summarize it into a unique list (removing some of what I deem 'junk') that is then easily searchable.

#!/bin/bash
DATE=`date +%Y-%m-%d_%H%M%S.%3N`
export HISTFILE=~/.bash_sessions/${DATE}.history
export HISTSIZE="INFINITE"
echo -e "\033[1;34mBash history saved to $HISTFILE (history -w to save latest)\033[0m"
alias dir="history -w;ls -lAF"

This runs on every terminal start (and SSH session).

Coupled with this:

alias hist='cat ~/allHistory.txt | grep '

will give a command to search the history summary (and colourize the search term too). Example:

$ hist docker
revert devops/local/docker-compose.yml
set | grep dockerdown
sudo tcpdump -N -A 'tcp port 80' -i docker0

On top of this, I have a cron job that runs hourly to summarize the command histories into the single searchable history file:

#!/bin/bash
cat $HOME/.bash_sessions/*.history $HOME/allHistory.txt | egrep -v "^(man |dir |cd |ps |cat |cp |hist |history |alias |which |top |tree |rm |rmdir )" | egrep -v -e '^(echo [^|]+)$' | grep -v " -help" | sort -u > $HOME/allHistory.new
mv $HOME/allHistory.new $HOME/allHistory.txt

An additional benefit is that the history from all terminals open do not mix, so when you attempt to re-run a command from Window1 that is 3 back in the history, you won't see commands from Window2, Window3 or Window4; which I find very helpful to keep command streams separate.

Another advantage is that I can purge the old window histories at any time because the summary will contain the "useful" commands for the future. You can also copy the history summary to another machine to benefit from work done on different machines.

It's simplistic, but it's also what I cobbled together in less than an hour. Maybe this will help?

Worst case, it might be a basis for something better?

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .