Last active
February 2, 2023 09:25
-
-
Save gatopeich/35d872335dc96e363ed104f3092fb48d to your computer and use it in GitHub Desktop.
Merge and keep bash history from different folders and processes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# BASH history merger by Agustín F. Pozuelo (c) 2023 | |
# Merge history files from multiple sessions, removing duplicate commands | |
# TODO: Maintain order of commands in the most recent appearances | |
# BASH history merger. | |
# I use this to maintain history of my many BASH sessions | |
# Each session writes history to a separate file | |
# Running this from inside .bashrc, the 10 most recent sessions are merged together | |
# duplicate lines are removed, then they are all sorted by timestamp and place in a new history file | |
# The new file is used throughout the session then saved | |
# My history settings: | |
export HISTCONTROL=ignoredups:erasedups # Avoid (only) consecutive dups | |
export HISTSIZE=20000 # Got 17846 as of January 2023 | |
export HISTFILESIZE=20000 | |
export HISTTIMEFORMAT="%F %T " | |
export HISTFILE="$HOME/.history-$(date +%Y%m%d)-$(basename $(pwd))-$$" | |
echo "Biggest story files:" | |
ls -Shs ~/.*history* | head | |
function merge_histories { | |
>&2 echo "Merging history files:" | |
>&2 ls -lh "$@" | |
for h in "$@"; do | |
unset timestamp | |
# N=0 | |
TS_PATTERN='^\#[0-9]{10}' | |
cat $h | while read -r line; do | |
# ((N+=1)) | |
if [[ $line =~ ^\#[0-9]{10} ]]; then | |
if [[ -v timestamp ]]; then | |
# >&2 echo "NUL between '$timestamp' and '$line'..." | |
echo -en '\0' | |
fi | |
timestamp=$line | |
# >&2 echo "Got TIMESTAMP=$timestamp ($h:$N)" | |
echo -n "$timestamp " | |
elif [[ -v timestamp ]]; then | |
# >&2 echo "Got COMMAND LINE=$line ($h:$N)" | |
echo "$line" | |
else | |
>&2 echo "No timestamps in file: $h" | |
# TODO: use the file's timestamp? "#$(stat -c%Y $h)" | |
break | |
fi | |
done | while read -rd $'\0' timestamp commands; do | |
# >&2 echo -e "$h:TIMESTAMP=$timestamp\n$h:COMMANDS=$commands" | |
echo -en "$commands $timestamp\0" | |
done | |
done |sort -zr| # r-sort to keep last timestamp for same command | |
while read -rd $'\0' l; do | |
timestamp=${l##*#} | |
# >&2 echo "GOT LINE: $l, timestamp=$timestamp" | |
echo -en "$timestamp ${l%#*}\0" # Replace timestamp in front and uniq by the rest | |
done |uniq -zf1|sort -z| # Unique and sort by timestamp | |
while read -rd $'\0' timestamp rest; do | |
echo -e "#$timestamp\n$rest" | |
# >&2 echo "WROTE TIMESTAMP=#$timestamp REST=$rest" | |
done | |
} | |
histories=$(ls -t1 ~/.*history*|head) # 10 most recent | |
merge_histories $histories > $HISTFILE | |
ls -lh $HISTFILE | |
history -r $HISTFILE | |
echo "History lines: $(history|wc -l)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment