🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.unix.shell
Article #4028

code: history auto management (for bash, but should be close to ksh)

#4028
From: S P Arif Sahari Wibowo
Date: Fri, 26 Sep 2008 15:09
126 lines
6360 bytes
Hi!

Just want to sharing some scripting code, and also RFC for 
improving it, if any.

Background: I am lazy and indecisive. :-) I did many long 
commands and one-liners that ended up reuse again and again, but 
it is difficult for me to decide in the beginning which one need 
to be saved and which one not, and I am too lazy too manage huge 
collections of small scripts manually.

Bash history keeping have been very helpful, but it has several 
limitation, especially since I tend to keep multiple shells open 
for weeks:
  - When the machine crashes (e.g. kid-induced power failure), 
all my history is lost.
  - History per shell can be huge, upon saving push out even not 
too old history just saved from other shell session.
  - Even though I setup generous HISTFILESIZE, one session that 
does not start properly can wipe out most of stuff from the 
history file.
  - Even if the shell support "erasedups" HISTCONTROL, 
duplication still occur in the file from multiple session. This 
will be loaded back into the shell taking history space.


So I wrote a set of scripts below, generally to automatically 
safe the history behind the scene and reduce duplication in 
loading. Maybe it can be useful for you too. Let me know if you 
have any suggestion. Specifically there are several complexity I 
introduced because of some considerations. Let me know if this 
considerations don't seem right:
  - Instead of just automatically save the history in a fix 
cycle, I try to do it in idle time, to reduce duplication of I 
work vigorously use the same commands again and again.
  - However, the calculation of idle time is such (idle time 
required is shorter and shorter) so eventually the history will 
be saved anyway.
  - In loading history, I put a lot of effort to avoid race 
condition where another session open and append to a history 
file just before it get overwritten, so: (a) instead of saving 
uniquely filtered history file to the original location, it 
saves to new file, and (b) in collection all previous history 
files, it is first renamed before read and deleted.
  - I have several multiple systems with different tools and file 
system, so the script start with try to guess which tools / 
features available and which are not and define functions to 
replace unavailable ones. Obviously not needed in a single or 
homogeneous environment.


So here it is:

########### History management ###########
# SPAS 2008IO - http://www.arifsaha.com/
# need license? How about LGPL, ok?
#
# to be incorporated into or called from bash startup script, such as .bashrc

if ! which tac ; then
   function tac() {
     tail -r "$@"
   }
fi

if [[ -d /proc ]] ; then
   function timelastactiv() {
     date -r "/proc/$1/fd/255" +"%s"
   }
elif ( stat --help | grep "%y.*modification" ) >/dev/null 2>&1 ; then
   function timelastactiv() {
     stat -f "%y" /dev/$(ps -otty -p "$1" | tail -1)
   }
else
   function timelastactiv() {
     stat -f "%m" /dev/$(ps -otty -p "$1" | tail -1)
   }
fi

case $- in
   *i* )   INTERACTIVE=1 ;;
esac
THISPID="$$"
HISTLOGFILE="/tmp/histmon.$(whoami).log"
HISTFILEBASE="$HOME/.bash_history"
HISTTMPBASE="$HOME/.bash_histtmp"

function routines() {
   history -a
   #echo -ne \\e[s\\e[1A$(date) history saved!\\e[u
   echo $THISPID, $(date) history saved! >> $HISTLOGFILE
}

if [[ ! "$HISTFILESIZE" ]] ; then HISTFILESIZE=4096 ;fi

if [[ "$INTERACTIVE" ]] ; then
   trap routines SIGUSR1
   WAITINI=$((2 * 3600))
   WAITSMALL=600
   LASTSAVE=0
   echo -n Shell $THISPID signalled by\
   ( trap "" SIGINT ; while WAITCUR=$WAITINI ; while TOUCHED=$(timelastactiv "$THISPID"); if [[ ! "$TOUCHED" ]] || [[ "$TOUCHED" -le "$LASTSAVE" ]] ; then IDLE=1 ; else IDLE=$(( $(date +"%s") - $TOUCHED )); fi ; echo $THISPID, $(date): $IDLE .. $WAITCUR >> $HISTLOGFILE ; [[ $IDLE -lt $WAITCUR ]] ; do WAITCUR=$(( $WAITCUR * 2 / 3 )) ; sleep $WAITSMALL ; done ; kill -s SIGUSR1 $THISPID ; do LASTSAVE=$(date +'%s'); sleep $WAITSMALL ; done & echo $!)

   HISTTMPCOLLECT=$(mktemp "$HISTTMPBASE.XXXXXXXX")
   { ls -rt "$HISTTMPBASE".* | while read -r fn ; do echo got work file "$fn" >&2 ; cat "$fn" ; done
     ls -rt "$HISTFILEBASE" "$HISTFILEBASE".* | while read -r fn ; do
       HISTTMP=$(mktemp "$HISTTMPCOLLECT.XXXXXXXX");
       if mv -f "$fn" "$HISTTMP" ; then echo got hist file "$fn" now "$HISTTMP" >&2 ; cat "$HISTTMP"
       else echo cannot mv "$fn" "$HISTTMP" >&2 ; cat "$fn" ; fi
     done
   } | nl -ba -s: -nrz | tac | sort -t: -u -k2.1 | sort -t: -n -k1,1 | cut -d: -f2- | tail -n $HISTFILESIZE > "$HISTTMPCOLLECT"
   history -r "$HISTTMPCOLLECT"
   HISTCOLLECT=$(mktemp "$HISTFILEBASE.XXXXXXXX")
   if mv -f "$HISTTMPCOLLECT" "$HISTCOLLECT" ; then rm "$HISTTMPCOLLECT".* ; fi
   HISTNEW=$(mktemp "$HISTFILEBASE.XXXXXXXX")
   if [[ -w "$HISTNEW" ]] ; then HISTFILE="$HISTNEW" ; fi
   echo load history from $(wc "$HISTCOLLECT") resulting $(history | wc -l) lines, save to "$HISTFILE"
fi



-- 
                              (stephan paul) Arif Sahari Wibowo
    _____  _____  _____  _____
   /____  /____/ /____/ /____
  _____/ /      /    / _____/      http://www.arifsaha.com/
Technical Details
Message-ID: <alpine.OSX.1.10.0809261024590.13605@imac2006.local>
Path: arc1-ca.pugleaf.net!g2news2.google.com!news1.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!news.k-dsl.de!feeder1.news.weretis.net!newsfeeder.dynfx.net!weretis.net!newsfeed.datemas.de!feed.cnntp.org!news.cnntp.org!not-for-mail

Show Full Headers
Complete Article Headers
X-Google-Thread: 1012a6,1b90defcc7ae87a1,start
X-Google-Thread: 1054c0,1b90defcc7ae87a1,start
X-Google-Attributes: gid1012a6,gid1054c0,domainid0,public,usenet
X-Google-Language: ENGLISH,ASCII-7-bit
Path: arc1-ca.pugleaf.net!g2news2.google.com!news1.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!news.k-dsl.de!feeder1.news.weretis.net!newsfeeder.dynfx.net!weretis.net!newsfeed.datemas.de!feed.cnntp.org!news.cnntp.org!not-for-mail
Newsgroups: comp.unix.shell,gnu.bash
Date: Fri, 26 Sep 2008 11:09:57 -0400
From: S P Arif Sahari Wibowo <arifsaha@yahoo.com>
Subject: code: history auto management (for bash, but should be close to
 ksh)
Message-ID: <alpine.OSX.1.10.0809261024590.13605@imac2006.local>
User-Agent: Alpine 1.10 (OSX 962 2008-03-14)
X-Archive: encrypt
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; format=flowed; charset=US-ASCII
Lines: 126
Organization: CNNTP
NNTP-Posting-Host: 1f7d9350.read.cnntp.org
X-Trace: DXC=AGHmC]ZXCA=iBm:2gM@Ib>WoT\PAgXa?1C4W9jWT_L:4BQ=;T6O1ba5Z]dged6hbF<eWTm_djkI`1GmQccMHM>L6
X-Complaints-To: abuse@cnntp.org