bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bash overwrites most history entries, if several instances run simultano


From: Roland Eggner
Subject: bash overwrites most history entries, if several instances run simultanously - WORKAROUND provided
Date: Mon, 6 Aug 2007 02:19:28 +0200
User-agent: KMail/1.9.6

Configuration Information [Automatically generated, do not change]:
Machine: i486
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='i486' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i486-pc-linux-gnu' 
-DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL 
-DHAVE_CONFIG_H   -I.  -I../bash -I../bash/include -I../bash/lib   -g -O2
uname output: Linux roland 2.6.18.5roland2 #1 Mon Mar 19 19:11:42 CET 2007 i686 
GNU/Linux
Machine Type: i486-pc-linux-gnu

Bash Version: 3.1
Patch Level: 17
Release Status: release

Description:
        bash overwrites most history entries, if several instances run
        simultanously

Repeat-By:
        Consider you have KDE with several konsole windows and several bash
        sessions running, you shut down KDE and want KDE session restoring
        after next time booting.
        With default configuration all bash instances try to write (almost)
        simultanously to the same ~/.bash_history, the last closing instance
        overwrites the new history entries of ALL OTHER instances which are
        SILENTLY LOST.
        If for your debugging and fixing more details of my configuration would
        be helpful, please mail me.

Fix:
        I tried some workarounds, this 2 may be useful for others:

Workaround 1:  usage of $PROMPT_COMMAND
---------------------------------------
        Searching Internet I found this suggestion for PROMPT_COMMAND (sorry,
        cannot remember URL), combined with HISTTIMEFORMAT and in /etc/fstab
        adding "commit=30" to ext3 mount options, it is my currently used
        workaround:

        # /etc/bash.bashrc
        # ----------------
        export HISTTIMEFORMAT="%Y%m%d.%H%M%S  "
        export PROMPT_COMMAND='history -a;history -c;history -r'

        # /etc/rc.local
        # -------------
        # eliminate older duplicates of history entries (HISTCONTROL=erasedups
        # works only occasionally), and keep backup files (in the past after
        # booting I found more than once surprisingly EMPTY ~/.bash_history,
        # probably because during previous shutdown multiple bash instances
        # tried to write simultanously and some failed)
        # ---------------------------------------------
        #!/bin/sh -e
        umask 0077
        for Home in /root /home/* ; do
                if [ -f $Home/.bash_history ] ; then
                        if [ -f $Home/.bash_history~0 ] ; then
                                if [ -f $Home/.bash_history~1 ] ; then
                                        if [ -f $Home/.bash_history~2 ] ; then
                                                mv $Home/.bash_history~{2,3}
                                        fi
                                        mv $Home/.bash_history~{1,2}
                                fi
                                mv $Home/.bash_history~{0,1}
                        fi
                        mv $Home/.bash_history{,~0}
                fi
                sed -re 'N;s/\`#([0-9]+)\n/\1:/' $Home/.bash_history~0 \
                        | sed -re '/^[0-9]+:.{1,4}$/d' \
                        | sort -unr -t : -k 1,1 | sort -u -t : -k 2 | sort -n 
-t : -k 1,1 \
                        | sed -re 's/^([0-9]+):/#\1\n/' > "$Home/.bash_history"
                chown --reference "$Home" "$Home/.bash_history"
        done
        exit 0

        HIGHLIGHT:
        ----------
        first time hitting key UP and getting history of just used commandlines
        from OTHER terminals may be a bit confusing, after some familiarization
        you will probably enjoy it!

        SHORTCOMING:
        ------------
        interactive "history -d" and "history -r" statements DON'T work, but
        luckily "vim $HISTFILE" WORKS


Workaround 2:  write separate history files for each $PID and terminal,
        consolidate them at next system boot
-----------------------------------------------------------------------
        NOT satisfying for me, bash history facilities buggy if filename
        $HISTFILE is longer than usual? (history -a takes NO effect, if
        HISTTIMEFORMAT is set history appears TWICE, ..)

        # /etc/bash.bashrc
        # ----------------
        if [[ ! "${HISTFILE:-}" =~ .bash_history.[1-9] ]] ; then
                # keep already set $HISTFILE if we are sourced again within the 
same bash instance
                HISTFILE="$( mktemp "$HOME/.bash_history.$$.$( readlink -fn 
/proc/$$/fd/1 | sed 's,/dev/,,;s,/,,g' ).XXXXXX" )"
                # separate files, each file name showing $PID and terminal it 
belongs to
        fi

        # /etc/rc.local  "normal version", assumes that there are
        # NO timestamps in history (HISTTIMEFORMAT not set)
        # -------------------------------------------------
        #!/bin/sh -e
        umask 0077
        for Home in /root /home/* ; do
                tDatei="$( mktemp "$Home/${0##*/}_bash_history.$$.XXXXXX" )"
                for BashHistory in $( find $Home -maxdepth 1 -name 
.bash_history.[1-9]\* -not -newer /var/log/boot -print0 | xargs -r -0 ls -tr ) 
; do
                        cat "$BashHistory" >> "$tDatei"
                        rm "$BashHistory"
                done
                if [ -s "$tDatei" ] ; then
                        [ -f $Home/.bash_history ]   && mv 
$Home/.bash_history{,~0}
                        gawk '/..../{print NR ":" $0;}' "$tDatei" | tac | sort 
-t : -k2 -u | sort -t : -k 1,1n | sed -r 's/^[0-9]+://' > "$Home/.bash_history"
                        # remove command lines shorter than 4 characters, of 
duplicates keep only youngest
                        chown -c --reference "$Home" "$Home/.bash_history"
                fi
                rm "$tDatei"
        done
        # SHORTCOMING: some NEW history entries appear at the beginning
        # of ~/.bash_history, but we want them at the end
        exit 0

        # /etc/rc.local  "DEBUGGING version", assumes that there are
        # NO timestamps in history (HISTTIMEFORMAT not set)
        # -------------------------------------------------
        #!/bin/sh -e
        umask 0077
        for Home in /root /home/* ; do
                tDatei="$( mktemp "$Home/${0##*/}_bash_history.$$.XXXXXX" )"
                for BashHistory in $( find $Home -maxdepth 1 -name 
.bash_history.[1-9]\* -not -newer /var/log/boot -print0 | xargs -r -0 ls -tr ) 
; do
                        cat "$BashHistory" >> "$tDatei"
                        # rm "$BashHistory"
                        echo "$BashHistory"
                # done
                done | tar -czf "${tDatei}.tgz" -T - --remove-files
                if [ -s "$tDatei" ] ; then
                        [ -f $Home/.bash_history~2 ] && mv 
$Home/.bash_history~{2,3}
                        [ -f $Home/.bash_history~1 ] && mv 
$Home/.bash_history~{1,2}
                        [ -f $Home/.bash_history~0 ] && mv 
$Home/.bash_history~{0,1}
                        [ -f $Home/.bash_history ]   && mv 
$Home/.bash_history{,~0}
                        gawk '/..../{print NR ":" $0;}' "$tDatei" | tac | sort 
-t : -k2 -u | sort -t : -k 1,1n | tee "${tDatei}.2" | sed -r 's/^[0-9]+://' > 
"$Home/.bash_history"
                        # remove command lines shorter than 4 characters, of 
duplicates keep only youngest
                        # chown -c --reference "$Home" "$Home/.bash_history"
                        chown -c --reference "$Home" "$Home/.bash_history" 
"$tDatei"{,.2,.tgz}
                fi
                # rm "$tDatei"
                gzip -9 "$tDatei"
        done
        exit 0





reply via email to

[Prev in Thread] Current Thread [Next in Thread]