just found a patch done by me some months ago, I have been using bash-4.2 with this patch for half a year, should be quite stable; it's mainly to implement unlimited .bash_history;
1) HISTFILESIZE has a bug that current bash manual saying if HISTFILESIZE is unset, then HISTFILE will be unlimited, but it seems there is no way to unset it in bash_profile or any rc file? 2) remove duplicates in HISTFILE also, not just in current history in memory, we can say this a deep dedup? it only run deep dedup when HC_ERASEDUPS set, Not sure if this can be applied to latest trunk code, but I can revamp it to latest tree if there are interests; Thanks, --- bash-4.2.orig/bashhist.c 2010-08-13 18:09:08.000000000 -0700 +++ bash-4.2/bashhist.c 2011-11-02 11:34:36.350166000 -0700 @@ -29,6 +29,8 @@ # include <unistd.h> #endif +#include <sys/mman.h> + #include "bashtypes.h" #include <stdio.h> #include <errno.h> @@ -281,9 +283,6 @@ load_history () set_if_not ("HISTSIZE", "500"); sv_histsize ("HISTSIZE"); - set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE")); - sv_histsize ("HISTFILESIZE"); - /* Read the history in HISTFILE into the history list. */ hf = get_string_value ("HISTFILE"); @@ -345,6 +344,69 @@ bash_delete_last_history () return r; } +int +erasedups_history (nelements, filename) + int nelements; + const char *filename; +{ + HIST_ENTRY *temp; + int r, fd, rv = 0; + size_t cursize, mmap_size; + char *buffer, *line, *lineend; + + fd = open (filename, O_RDWR); + + if (fd < 0) + return errno; + + cursize = lseek (fd, 0, SEEK_END); + + using_history (); + + mmap_size = cursize +1; /* for possibly not newline ending */ + buffer = mmap (0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if ((void *)buffer == MAP_FAILED) + { + rv = errno; + close (fd); + return rv; + } + + line = buffer; + while (line < buffer+cursize) { + lineend = strchr (line, '\n'); + + if (!lineend) { /* last line not newline ending? */ + lineend = line + strlen(line); + *lineend = '\n'; + buffer[++cursize] = '\0'; + } + + for (r = 0; (temp = previous_history ()) && r < nelements; r++) + if (STREQN (line, temp->line, strlen (temp->line))) { + memmove (line, lineend+1, (buffer+cursize) - (lineend+1)); + cursize -= (lineend+1 - line); + buffer[cursize] = '\0'; + lineend = NULL; + break; + } + using_history (); + + if (lineend) + line = lineend+1; + } + + if (ftruncate (fd, cursize) == -1) + rv = errno; + if (!rv && msync (buffer, cursize, 0) == -1) + rv = errno; + if (!rv && munmap (buffer, mmap_size) == -1) + rv = errno; + close (fd); + + return rv; +} + #ifdef INCLUDE_UNUSED /* Write the existing history out to the history file. */ void @@ -389,9 +451,16 @@ maybe_append_history (filename) } close (fd); } + if (history_control & HC_ERASEDUPS) + erasedups_history (history_lines_this_session, filename); result = append_history (history_lines_this_session, filename); history_lines_in_file += history_lines_this_session; - history_lines_this_session = 0; + + { + char *hf = get_string_value ("HISTFILE"); + if (hf && *hf && !strcmp(hf, filename)) + history_lines_this_session = 0; + } } return (result); } @@ -426,6 +495,8 @@ maybe_save_shell_history () using_history (); if (history_lines_this_session <= where_history () || force_append_history) { + if (history_control & HC_ERASEDUPS) + erasedups_history (history_lines_this_session, hf); result = append_history (history_lines_this_session, hf); history_lines_in_file += history_lines_this_session; } -- Cheng Renquan (程任全)