🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.unix.shell
Article #4018

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

#4018
From: S P Arif Sahari Wibowo
Date: Sun, 13 Sep 2009 15:16
132 lines
6852 bytes
Some small fixes:

########### History management ###########
# SPAS 2008IO, 2008IR, 2009HM - http://www.arifsaha.com/
# Licensed under LGPLv3 - http://www.gnu.org/copyleft/lesser.html
#
# to be incorporated into or sourced from bash startup script, such as .bashrc

case $- in
   *i* )   INTERACTIVE=1 ;;
esac
ThisPID="$$"
HISTLogFile="/tmp/histmon.$(whoami).log"
HISTFileBase="$HOME/.bash_history"
HISTTmpBase="$HOME/.bash_histtmp"

# In some system 'which' never fails,
# requiring secondary check as below, duh!
if [[ ! -x $(which tac) ]] ; then
   #echo define tac function >&2
   function tac() {
     tail -r "$@"
   }
fi

# define function to get the last time
# any activity in the tty of a process
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

function routines() {
   if history -a ; then
     #echo -ne \\e[s\\e[1A$(date) history saved!\\e[u >&2
     echo $ThisPID by $SignallerPID, $(date) history saved to $HISTFILE! >> $HISTLogFile
   else
     echo $ThisPID by $SignallerPID, $(date) history saving to $HISTFILE failed! >> $HISTLogFile
   fi
}

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

if [[ "$INTERACTIVE" ]] ; then
   trap routines SIGUSR1
   WaitIni=$((2 * 3600))
   WaitSmall=600
   LastSave=0
   # Routine below run a background loop that
   # will signal the shell to save history after some time.
   # Instead of fix periods, it try to do it in idle time,
   # to reduce duplication caused by vigorous work
   # using the same commands again and again.
   # However, the calculation of idle time required is shorter over time,
   # so it assure that the history saving signal will be sent after some time.
   ( 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 ) &
   SignallerPID="$!"
   echo shell $ThisPID signalled by $SignallerPID >&2

   HISTTmpCollect=$(mktemp "$HISTTmpBase.XXXXXXXX")
   {
     # Routine below collects files being worked on
     # by other instance of this script:
     ls -rt "$HISTTmpBase".* 2>/dev/null | while read -r afile ; do echo got work file "$afile" >&2 ; cat "$afile" ; done

     # Routine below collects history files by previous sessions:
     ls -rt "$HISTFileBase" "$HISTFileBase".* 2>/dev/null | while read -r afile ; do
       # To avoid other session open & append the history file
       # just after being read and before deleted,
       # each file is renamed before read:
       HISTTmp=$(mktemp "$HISTTmpCollect.XXXXXXXX");
       if mv -f "$afile" "$HISTTmp" ; then echo got hist file "$afile" now "$HISTTmp" >&2 ; cat "$HISTTmp"
       else echo cannot mv "$afile" "$HISTTmp" >&2 ; cat "$afile" ; fi
     done
   } | tac | awk '!seen[$0]++ && NOUT++<'$HISTFILESIZE | tac > "$HISTTmpCollect"
   #  nl -ba -s: -nrz | tac | sort -t: -u -k2.1 | sort -t: -n -k1,1 | cut -d: -f2- | tail -n $HISTFILESIZE > "$HISTTmpCollect"
   # The phrase above will filter out duplicate,
   # keeping the order, keeping last occurrence of any duplicate.
   # The result saved to a new file, not original history file
   # to avoid other session open & append the original history file
   # just before it being overwritten.
   # Note that race condition can still occur in reading the history file:
   # it is possible a session started at the same time grab
   # a history file and rename it before it can be read
   # but just after collecting work file is done.
   # So some history may not get loaded.
   # But this is less big deal since the information is not
   # lost and next session will be able to read it.

   # Saity check whether the pipe was actually successful:
   # (alternatively bash' PIPESTATUS can be used,
   # just it will make it harder to port to other shell)
   if [[ -s "$HISTTmpCollect" ]] ; then
     history -r "$HISTTmpCollect"
     HISTCollect=$(mktemp "$HISTFileBase.XXXXXXXX")
     if mv "$HISTTmpCollect" "$HISTCollect" ; then rm "$HISTTmpCollect".* ; fi

     # Actual history saving file is another new history file
     # instead of the new combined old history
     # to keep better ordering of history (i.e. newer history file
     # not to be put behind the old one):
     HISTNew=$(mktemp "$HISTFileBase.XXXXXXXX")
     touch "$HISTNew"
     if [[ -w "$HISTNew" ]] ; then HISTFILE="$HISTNew" ; fi
   else
     rm "$HISTTmpCollect"
   fi

   # Move back any work file left over because of some failures:
   ls -rt "$HISTTmpCollect".* 2>/dev/null | while read -r afile ; do
     HISTTmp=$(mktemp "$HISTFileBase.XXXXXXXX");
     mv "$afile" "$HISTTmp"
     echo mv back "$afile" "$HISTTmp" >&2
   done
   echo load history from $(wc "$HISTCollect") resulting $(history | wc -l) lines, save to "$HISTFILE" >&2
fi



-- 
    ____  ____  ____  ____ (stephan paul) Arif Sahari Wibowo
   /___  /___/ /___/ /___      http://www.arifsaha.com/
  ____/ /     /   / ____/
Technical Details
Message-ID: <alpine.OSX.2.00.0909131108470.4830@imac2006.local>
Path: arc1-ca.pugleaf.net!g2news2.google.com!news3.google.com!feeder1-2.proxad.net!proxad.net!feeder1-1.proxad.net!club-internet.fr!feedme-small.clubint.net!news01.khis.de!feed.cnntp.org!news.cnntp.org!not-for-mail
References: <alpine.OSX.1.10.0809261024590.13605@imac2006.local> <48dd0915$0$33600$742ec2ed@news.sonic.net> <alpine.OSX.1.10.0809271102250.13605@imac2006.local> <alpine.OSX.1.10.0809282053010.22505@imac2006.local>

Show Full Headers
Complete Article Headers
X-Google-Thread: 4d82dd0a1,1b90defcc7ae87a1
X-Google-Attributes: gid4d82dd0a1,public,usenet
X-Google-NewGroupId: yes
X-Google-Language: ENGLISH,ASCII-7-bit
Path: arc1-ca.pugleaf.net!g2news2.google.com!news3.google.com!feeder1-2.proxad.net!proxad.net!feeder1-1.proxad.net!club-internet.fr!feedme-small.clubint.net!news01.khis.de!feed.cnntp.org!news.cnntp.org!not-for-mail
Newsgroups: comp.unix.shell,gnu.bash
Date: Sun, 13 Sep 2009 11:16:01 -0400
From: S P Arif Sahari Wibowo <arifsaha@yahoo.com>
Subject: Re: code: history auto management (for bash, but should be close to
 ksh)
In-Reply-To: <alpine.OSX.1.10.0809282053010.22505@imac2006.local>
Message-ID: <alpine.OSX.2.00.0909131108470.4830@imac2006.local>
References: <alpine.OSX.1.10.0809261024590.13605@imac2006.local> <48dd0915$0$33600$742ec2ed@news.sonic.net> <alpine.OSX.1.10.0809271102250.13605@imac2006.local> <alpine.OSX.1.10.0809282053010.22505@imac2006.local>
User-Agent: Alpine 2.00 (OSX 1167 2008-08-23)
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; format=flowed; charset=US-ASCII
Lines: 132
Organization: CNNTP
NNTP-Posting-Host: a002e668.read.cnntp.org
X-Trace: DXC=RAg[`P[cTkaFd<l<6;WcijWoT\PAgXa?a]`:egb9Ga8mN\9@jkfRE<d2;a0CKmIHk`Lm?Hm?DRK?mZ\7\>EmYoMf
X-Complaints-To: abuse@cnntp.org