Article View: comp.unix.shell
Article #4029Re: code: history auto management (for bash, but should be close to ksh)
From: S P Arif Sahari Wibowo
Date: Sat, 27 Sep 2008 15:58
Date: Sat, 27 Sep 2008 15:58
161 lines
8075 bytes
8075 bytes
On Fri, 26 Sep 2008, Icarus Sparry wrote:
> If you are going to number the lines and then do sorts on them
> then you don't need to reverse the lines.
The numbering and sorting on it is to keep the original
ordering. Reverse the lines it to make sure the last occurence
of each duplication are kept.
> I suggest a
> tac | print_line_first_time_seen | head -n | tac
> pipeline would be better. print_line_first_time_seen is
> usually done as
> awk '!seen[$0]++'
Thanks! I choose the sort method before because I believe it is
more "general" in term of it does not depend on ability to put
the whole file in memory (works for large files). Obviously it
will be hardly the issue with history files. I tested your
method and it seems to be a bit faster. I keep the original line
commented nearby in-case someone one to use 1 GB history files.
:-)
> I find the long variables names bad, It took several reads to
> see that HISTTMPBASE and HISTFILEBASE were different.
Well, it was from mixed influences. I used to long file name in
Pascal, but off course there it is camel-cased. The all capital
influenced by common environment variable naming. I principally
generally favor more explanatory variable name (since data
structure is more important than algorithm in programming). In
any case, I am changing the variable name to more camel case,
hopefully it more understandable.
I don't see any code repetition can be saved by creating
function, but I also trying comment more also to get better
separation between code sections.
> if there are race conditions with multiple shells running at
> the same time, but it certainly looks as if there are issues.
There is definitely one in reading the history file: it is
possible to missed some files. But information is not lost and
next session should got them. Also, there can be an issue with
any process that open a file for extended time, but hard to get
around it without mandatory locking and shell process should not
do that, right?
So here is the improved code:
########### History management ###########
# SPAS 2008IO - 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"
if ! which tac ; then
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
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 $! )
echo -n Shell $ThisPID signalled by" "
HISTTmpCollect=$(mktemp "$HISTTmpBase.XXXXXXXX")
{
# Routine below collects files being worked on
# by other instance of this script:
ls -rt "$HISTTmpBase".* | 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".* | 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.
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
echo load history from $(wc "$HISTCollect") resulting $(history | wc -l) lines, save to "$HISTFILE"
fi
--
(stephan paul) Arif Sahari Wibowo
_____ _____ _____ _____
/____ /____/ /____/ /____
_____/ / / / _____/ http://www.arifsaha.com/
Disclaimer: IANAL, IANALP, IANAMD, IANAMP, IANAAP
my statements - if any - should be treated as such.
Technical Details
Message-ID:
<alpine.OSX.1.10.0809271102250.13605@imac2006.local>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news.germany.com!feeder1.news.weretis.net!newsfeeder.dynfx.net!weretis.net!news.szaf.org!feeder06.uucp-net.de!news.uucp.at!feed.cnntp.org!news.cnntp.org!not-for-mailReferences:
<alpine.OSX.1.10.0809261024590.13605@imac2006.local> <48dd0915$0$33600$742ec2ed@news.sonic.net>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!news3.google.com!news.germany.com!feeder1.news.weretis.net!newsfeeder.dynfx.net!weretis.net!news.szaf.org!feeder06.uucp-net.de!news.uucp.at!feed.cnntp.org!news.cnntp.org!not-for-mail Newsgroups: comp.unix.shell,gnu.bash Date: Sat, 27 Sep 2008 11:58:26 -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: <48dd0915$0$33600$742ec2ed@news.sonic.net> Message-ID: <alpine.OSX.1.10.0809271102250.13605@imac2006.local> References: <alpine.OSX.1.10.0809261024590.13605@imac2006.local> <48dd0915$0$33600$742ec2ed@news.sonic.net> User-Agent: Alpine 1.10 (OSX 962 2008-03-14) X-Archive: encrypt MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Lines: 161 Organization: CNNTP NNTP-Posting-Host: 0d5fa549.read.cnntp.org X-Trace: DXC=^dRDUX1h]7YS03?DM:TjdRWoT\PAgXa?QU_T_E47UJoXBQ=;T6O1baUZ]dged6hbF\WCL;1A^C63\l1dXKZC9V2Z X-Complaints-To: abuse@cnntp.org