Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-1-anderson committed Nov 7, 2012
0 parents commit 8e2f2af
Show file tree
Hide file tree
Showing 2 changed files with 263 additions and 0 deletions.
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
HISTORY RECALL PROJECT

Manage bash history from multiple terminal windows in a sane and
rational way.

For a quick start, scroll down for installation and usage.


INTRODUCTION

----------------------------------------------------
> Those who forget the past are doomed to retype it.
> - [George Santayana][1] (paraphrased)
----------------------------------------------------

The history recall project helps organize your bash history.
If you have ever been in the position where you are trying
to find the one terminal window that you used to enter an
obscure command so that you can use your bash history to
recall it, then you may be looking for a better way to manage
your history.

Aside: Note that if you would like to share a single
bash history across *all* of your terminal windows, there
is a simple solution:

$ unset HISTFILESIZE
$ export PROMPT_COMMAND="history -a"
$ shopt -s histappend

For more information on this, see [The Definitive Guide to
Bash Command Line History][2]. If, however, you are accustomed
to doing different tasks in different terminals, and in general
*like* the fact that your history is segregated by terminal window,
then a more complicated solution may meet your needs better.
History Recall is just such a solution.


USAGE

Docs to-be-written. See the script itself.


INSTALLATION

The History Recall commands are all implemented as bash functions
defined in a single historyrc file. To install, all that you need
to do is source this file. First, clone the project from github:

cd ~/local
git clone https://github.com/greg-1-anderson/history-recall

Then source the file when your bash shell starts up.

*In ~/.bashrc
source ~/local/history-recall/historyrc

Once you have installed History Recall, you must either re-source
your .bashrc file or close and re-open your terminal windows.
Once you do this, your bash history will be saved in a separate file
for each terminal window, and your history will persist across reboots.

Nifty.


[1]: http://en.wikipedia.org/wiki/George_Santayana
[2]: http://www.catonmat.net/blog/the-definitive-guide-to-bash-command-line-history/

195 changes: 195 additions & 0 deletions historyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# History configuration
# c.f. http://www.catonmat.net/blog/the-definitive-guide-to-bash-command-line-history/
shopt -s histappend
shopt -s histreedit
mkdir -p $HOME/.history
# If $HISTFILE is in the home directory, then make a new history file unique to this tty
if [ $(dirname "$HISTFILE") == "$HOME" ]
then
TTY=$(tty | tr / _)
HOSTNAME=$(hostname -s)
export HISTFILE="$HOME/.history/bash_${HOSTNAME}${TTY}"
if [ -f "$HISTFILE" ]
then
history -r
fi
fi
export HISTIGNORE="&:[ ]*:ls:hist.*:exit"
export PROMPT_COMMAND="$PROMPT_COMMAND"'; HISTTIMEFORMAT="[%m/%d@%H:%M:%S] " history -a'

# Print command history including execution times, for this run of 'history' only
alias histt='HISTTIMEFORMAT="[%m/%d@%H:%M:%S] " history'

# Make a note in command history
# Usage:
# $ note COMMAND // comment
# command output
# $ recall comment
# command output
# The 'note' command embeds the output of the supplied command
# into the bash history file. This command output may be printed
# out again verbatim later with the 'recall' command.
function note {
t=$(date "+%s")
p=();
c=false
for a in "$@";
do
if $c || [ "x$a" == "x//" ]
then
c=true
else
p[${#p[@]}]="$a";
fi
done
echo "#$t >>" $* >> $HISTFILE
COLUMNS=$((COLUMNS-5-${#t})) "${p[@]}" | sed -e "s/^/#$t :: /" | tee -a $HISTFILE | sed -e 's/^#[^:]*:: //'
}

# Begin a new task: switch to a new command history
# file, and make a note in it. We'll copy existing
# history over, just in case we did some stuff relevant
# to the current task before declaring it.
# Usage:
# $ task Install whizzy-fu pro
# begin task: Install whizzy-fu pro
# $ sudu apt-get install whizzyfu libwhizzyfu-dev
# $ ... lots of other stuff
# $ finished
# finished task: Install whizzy-fu pro
#
# ... a few days later, in a different terminal:
# $ recall whizzy
# # Fri Oct 12 11:06:43 PDT 2012
# recalled task: Install whizzy-fu pro
# $ ^Rapt-get
# (reverse-i-search)`sudo apt-get': sudo apt-get install whizzyfu libwhizzyfu-dev
function task {
t=$(date "+%s")
task=$(echo $* | tr A-Z a-z | sed -e 's/ /_/g' -e 's/[^a-z0-9_]//g')
taskfile="$HOME/.history/task_$task"
history -a
histpush "$taskfile"
note echo "begin task: $*" // $HISTFILE
echo "HISTFILE is now $HISTFILE"
}

# Complete a task and go back to previous HISTFILE. Optional.
function finished {
l=$(grep "^#[0-9]\+ :: begin task:" $HISTFILE | tail -n 1)
if [ -z "$l" ]
then
echo "finished: no task in progress"
else
m=$(echo $l | sed -e 's/^#[^>]*:: begin/finished/')
echo $m
histpop
fi
}

# Show all active nested tasks in this terminal
function tasks {
for f in $HISTFILE $(echo $HISTFILES | tr : ' ') ; do
if [ ${f:0:1} != '/' ]
then
f="$HOME/.history/$f"
fi
l=$(grep -Hm 1 "^#[0-9]\+ >>.*$*" $f)
t=$(echo $l | sed -e 's/^[^#]*#\([0-9]\+\).*/\1/')
c=$(echo $l | sed -e 's/^[^>]*>> *//')
d=$(date --date="@$t")
n=${c#*:}
sn=${n%% //*}
echo "$(basename $f):$sn // $d"
done
}

# grep all history files for a command pattern
function hgrep {
(
cd $HOME/.history
grep $* $HISTFILE $(ls -t | grep -v $(basename $HISTFILE)) | grep -v '^[^:]*:#'
)
}

# Show the output of a command passed to 'note', or switch back to a
# task (and corresponding history file) from the past.
function recall {
l=$(cd $HOME/.history && grep "^#[0-9]\+ >>.*$*" $HISTFILE $(ls -t) | tail -n 1)
if [ -z "$l" ]
then
echo "recall: cannot find $*: No such note or task"
else
f=$(echo $l | sed -e 's/^\([^:]*\):#.*/\1/')
if [ ${f:0:1} != '/' ]
then
f="$HOME/.history/$f"
fi
t=$(echo $l | sed -e 's/^[^#]*#\([0-9]\+\).*/\1/')
c=$(echo $l | sed -e 's/^[^>]*>> *//')
d=$(date --date="@$t")
if [ "${c%%:*}" == "echo begin task" ]
then
n=${c#*:}
if [ "$HISTFILE" == "$f" ]
then
echo "# $d"
echo "${c#* }"
else
echo "# $d"
echo "resume task: $n"
histpush "$f"
echo "HISTFILE is now $HISTFILE"
fi
else
if [ "$HISTFILE" != "$f" ]
then
echo "recall: found note in $f"
fi
if [ "${c%% *}" == "echo" ]
then
echo "# $d"
echo "${c#* }"
else
echo "# $d"
echo "\$ $c"
grep "#$t :: " $HISTFILE | sed -e 's/^#[0-9]* :: //'
fi
fi
fi
}

# Start using a new history file. Keep a stack of previous
# history files so they may be returned to at a later time.
function histpush {
if [ -n "$1" ]
then
if [ -n "$HISTFILES" ]
then
export HISTFILES="$HISTFILE"
else
export HISTFILES="$HISTFILES:$HISTFILE"
fi
export HISTFILE="$1"
history -r
fi
}

# Resume using a history file that was in use in the past.
function histpop {
if [ -n "$HISTFILES" ]
then
export HISTFILE="${HISTFILES%%:*}"
history -r
if [ "${HISTFILES/:/}" == "$HISTFILES" ]
then
export HISTFILES=
else
export HISTFILES="${HISTFILES#*:}"
fi
else
echo "histpop: HISTFILES is empty"
fi
echo "HISTFILE restored to $HISTFILE"
}

0 comments on commit 8e2f2af

Please sign in to comment.