1

I want a reliable solution to hold every command in every terminal-tab in my bash history?

With timestamps, ordered, last commands last, and unique.

While open, each tab has its own list, so that I can use history expansion with PS1.

And new tabs take as the basis all the current and past commands.

2

I have all my stuff in a single file, .bash_aliases, which get sourced in .bashrc:

HISTMY="$HOME/.bash_history"    
touch $HISTMY

HISTSIZE=-1
HISTFILESIZE=-1
HISTCONTROL='ignoredups:ignorespace'
HISTTIMEFORMAT="|%d.%m._%a_%T|  "
HISTMYTERM=${HISTMY}_`tty|sed 's|^/dev/||;s|/|_|g'`

PROMPT_COMMAND='history -a $HISTMYTERM'

export MYHISTLOCK="/tmp/.my.hist.lock"

every tab has his file: .bash_history_pts_{0..}
plus the current .bash_history with old stuff

FBashHist ()
{
    local perl_history=$(cat <<'EOF'
########################################
#line 1526
use v5.10;

$file = $ARGV[0];
@ARGV = glob "$file*";

$time = "#" . (time - 1_000_000);

while (<>) {
    s/^\s*//;
    s/\s*$//;

    next if length() < 4;

    if (/^#\d{9,}$/) {
        $time = $_;
    }
    else {
        $cmd = $_;

        if (exists $hash{$cmd}) {
            next if $hash{$cmd} ge $time;
        }
        $hash{$cmd} = $time;
    }
}

@keys = sort { $hash{$a} cmp $hash{$b} } keys %hash;

@keys = reverse @keys;
@keys = splice(@keys, 0, 8000);  # cmds to save
@keys = reverse @keys;

foreach $key ( @keys ) {
    push @hist, "$hash{$key}\n$key\n";
}

open BA, ">$file" or die "cant open '$file' for write: $!";
print BA @hist;
close BA;

EOF
)
###############################

perl -E "$perl_history" $HISTMY
}

A perl hash is per se unique, so I use it for commands. The values are the timestamps.

It must be ensured that this init runs on reboot for all tabs only once.

I use flock from util-linux. It creates an empty file, which locks the tabs. With append (>>), later runs don't reset it.

After 10 seconds, more than enough time to init, a rerun is possible.

### call with init lock
(
    flock -x 9

    if [ ! -s $MYHISTLOCK ]; then
        echo $$ >$MYHISTLOCK

        FBashHist
    else
        l=`stat -c %Y $MYHISTLOCK`

        (( $l )) && d=`date +%s` && ((d -= 10))

        if (( $l < $d )); then
            touch $MYHISTLOCK

            FBashHist
        fi
    fi
) 9>>$MYHISTLOCK
sleep 1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.