Article View: comp.unix.shell
Article #4030Re: code: history auto management (for bash, but should be close to ksh)
From: S P Arif Sahari Wibowo
Date: Mon, 29 Sep 2008 00:55
Date: Mon, 29 Sep 2008 00:55
129 lines
6800 bytes
6800 bytes
Updated version, now include sanity check: in case processing
fails, not to remove older history files.
########### History management ###########
# SPAS 2008IO, 2008IR - http://www.arifsaha.com/
# need license? How about LGPL, ok?
#
# 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 tag 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() {
history -a
#echo -ne \\e[s\\e[1A$(date) history saved!\\e[u >&2
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
# 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 & echo -n $! >&2 )
echo " "signalling shell $ThisPID >&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]++' | head -n $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")
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.1.10.0809282053010.22505@imac2006.local>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news1.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!tiscali!newsfeed1.ip.tiscali.net!195.208.113.2.MISMATCH!goblin2!goblin.stu.neva.ru!feed.cnntp.org!news.cnntp.org!not-for-mailReferences:
<alpine.OSX.1.10.0809261024590.13605@imac2006.local> <48dd0915$0$33600$742ec2ed@news.sonic.net> <alpine.OSX.1.10.0809271102250.13605@imac2006.local>Show Full Headers
Complete Article Headers
X-Google-Thread: 1012a6,1b90defcc7ae87a1 X-Google-Thread: 1054c0,1b90defcc7ae87a1 X-Google-Attributes: gid1012a6,gid1054c0,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: arc1-ca.pugleaf.net!g2news1.google.com!news1.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!tiscali!newsfeed1.ip.tiscali.net!195.208.113.2.MISMATCH!goblin2!goblin.stu.neva.ru!feed.cnntp.org!news.cnntp.org!not-for-mail Newsgroups: comp.unix.shell,gnu.bash Date: Sun, 28 Sep 2008 20:55:07 -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.0809271102250.13605@imac2006.local> Message-ID: <alpine.OSX.1.10.0809282053010.22505@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> 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: 129 Organization: CNNTP NNTP-Posting-Host: 1ea19a15.read.cnntp.org X-Trace: DXC=5[[IRC3?=1N?ZNgFG`EG\IWoT\PAgXa?AC4W9jWT_L:DBQ=;T6O1baEZ]dged6hbFLbKn>=1b3\MJc`a91_Q?Wn@ X-Complaints-To: abuse@cnntp.org