Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

First of all, this is not a duplicate of any existing threads on SE. I have read these two threads (1st, 2nd) on better bash history, but none of the answers work - - I am on Fedora 15 by the way.

I added the following to the .bashrc file in the user directory (/home/aahan/), and it doesn't work. Anyone has a clue?

HISTCONTROL=ignoredups:erasedups  # no duplicate entries
HISTSIZE=1000                     # custom history size
HISTFILESIZE=100000                 # custom history file size
shopt -s histappend                      # append to history, don't overwrite it
PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"  # Save and reload the history after each command finishes

Okay this is what I want with the bash history (priority):

  • don't store duplicates, erase any existing ones
  • immediately share history with all open terminals
  • always append history, not overwrite it
  • store multi-line commands as a single command (which is off by default)
  • what's the default History size and history file size?
share|improve this question
    
bump! anyone? Nothing works. Could this be a problem with Fedora 15 (with Gnome 3 and running on a Windows host virtual machine)? –  its_me Aug 7 '11 at 17:53
    
Please don't "bump" posts here. If they aren't getting answered you need to ask more clearly, include the right bits of context clues, or something. If you need attention on your posts you can issue bounties that help get more people paying them more attention. –  Caleb Aug 8 '11 at 20:07
1  
Are you sure you are even using bash? (echo $SHELL). Do the settings work if you run them manually from your open shell? Obviously since they do work for so many others the settings are right, you are just implementing them wrong. And no Fedora15/Gnome3/being a virtual machine have little to do with the actual function of bash. –  Caleb Aug 8 '11 at 20:08
    
@Caleb, first sorry about bumping the post. Also, I tried my best to be very clear. No, I haven't issued them in the shell. I just copy-pasted them into .bashrc file. Is that wrong? Can you add an "answer" to this post with the actual shell commands? (please bear with my noob-ity.) –  its_me Aug 8 '11 at 20:25
1  
Everything you write in scripts or .bashrc ARE actual shell commands. Scripts are just series of shell commands. Also the edit you recently made removing the export bit was a bad idea, that should be kept. –  Caleb Aug 8 '11 at 20:47

4 Answers 4

up vote 23 down vote accepted
+50

This is actually a really interesting behavior and I confess I have greatly underestimated the question at the beginning. But first the facts:

1. What works

The functionality can be achieved in several ways, though each works a bit differently. Note that, in each case, to have the history "transferred" to another terminal (updated), one has to press Enter in the terminal, where he/she wants to retrieve the history.

  • option 1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"
    

    This has two drawbacks:

    1. At login (opening a terminal), the last command from the history file is read twice into the current terminal's history buffer;
    2. The buffers of different terminals do not stay in sync with the history file.
  • option 2:

    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"
    

    (Yes, no need for shopt -s histappend and yes, it has to be history -c in the middle of PROMPT_COMMAND) This version has also two important drawbacks:

    1. The history file has to be initialized. It has to contain at least one non-empty line (can be anything).
    2. The history command can give false output - see below.

[Edit] "And the winner is..."

  • option 3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    PROMPT_COMMAND="history -n; history -w; history -c; history -r; $PROMPT_COMMAND"
    

    This is as far as it gets. It is the only option to have both erasedups and common history working simultaneously. This is probably the final solution to all your problems, Aahan.


2. Why does option 2 not seem to work (or: what really doesn't work as expected)?

As I mentioned, each of the above solutions works differently. But the most misleading interpretation of how the settings work comes from analysing the output of history command. In many cases, the command can give false output. Why? Because it is executed before the sequence of other history commands contained in the PROMPT_COMMAND! However, when using the second or third option, one can monitor the changes of .bash_history contents (using watch -n1 "tail -n20 .bash_history" for example) and see what the real history is.

3. Why option 3 is so complicated?

It all lies in the way erasedups works. As the bash manual states, "(...) erasedups causes all previous lines matching the current line to be removed from the history list before that line is saved". So this is really what the OP wanted (and not just, as I previously thought, to have no duplicates appearing in sequence). Here's why each of the history -. commands either has to or can not be in the PROMPT_COMMAND:

  • history -n has to be there before history -w to read from .bash_history the commands saved from any other terminal,

  • history -w has to be there in order to save the history to file and erase duplicates,

  • history -a must not be placed there instead of history -w, because it does not trigger erasing duplicates,

  • history -c is also needed because it prevents trashing the history buffer after each command,

  • and finally, history -r is needed to restore the history buffer from file, thus finally making the history shared across terminal sessions.

share|improve this answer
    
Actually, the history sharing among terminals is working flawlessly for me. But I can't prevent history duplication. That's the only issue ATM. –  its_me Aug 9 '11 at 23:27
1  
+1 for "But the most misleading interpretation of how the settings work comes from analysing the output of history command." I think this is the core of the OP's issue. Excellent deduction. –  jasonwryan Aug 9 '11 at 23:29
    
Have you read the whole explanation and tested by tail -f .bash_history? This is much more complicated than it seems. See also my comment under your own answer. –  rozcietrzewiacz Aug 9 '11 at 23:29
    
yes, I tried $ tail -f .bash_history and it listed the commands history (but without IDs - - i.e., unlike $ history). Like I said, I am (still) unable to prevent duplication. Does your above answer in a way imply that preventing history duplication is not possible? You gotta see this as well. –  its_me Aug 9 '11 at 23:42
1  
I finally saw your point. By 'duplicates' you meant something else than myself. I only focused at sequences of the same command. Updated my answer - see "option 3". Also, for your case, to test how the history works you should actually use watch "tail -n 20 .bash_history" instead of the tail -f .bash_history. –  rozcietrzewiacz Aug 10 '11 at 7:43

In your prompt command, you are using the -c switch. From man bash:

-c   Clear the history list by deleting all the entries

To share your history with all open terminals, you can use -n:

-n   Read the history lines not already read from the history file into the current history list. These are lines appended to the history file since the beginning of the current bash session.

The default size is also in the manual:

HISTSIZE The number of commands to remember in the command history (see HISTORY below). The default value is 500.

To save multi-line commands:

The cmdhist shell option, if enabled, causes the shell to attempt to save each line of a multi-line command in the same history entry, adding semicolons where necessary to preserve syntactic correctness. The lithist shell option causes the shell to save the command with embedded newlines instead of semicolons.

Also, you shouldn't preface HIST* commands with export — they are bash-only variables not environmental variables: HISTCONTROL=ignoredups:erasedups is sufficient.

share|improve this answer
    
So, this export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND" is correct? Also, do you know how I can make the history file store multi-line commands as a single command (which is off by default)?? –  its_me Aug 7 '11 at 7:52
1  
Yes. As per the man page quoted above, shopt -s cmdhist will save multi-lines. –  jasonwryan Aug 7 '11 at 8:12
    
okay, I tried 'em all. Looks like HISTCONTROL=ignoredups:erasedups is not working. I also tried having just that in the .bashrc file (among custom functions). Any idea what could be wrong? I am using Fedora 15 on a virtual machine - - Windows 7 host. –  its_me Aug 7 '11 at 8:15
    
Make sure there is nothing in the other startup files, like /etc/bashrc, .bash_profile etc that is overriding it. –  jasonwryan Aug 7 '11 at 8:26
    
I dont see any issues with the .bash_profile file. As for the content in /etc/bashrc I put it here, please take a look - pastebin.com/Uae6sE6s –  its_me Aug 7 '11 at 8:33

Use this instead:

HISTCONTROL=ignoreboth
share|improve this answer

This is what I came up with and I am happy with it so far...

alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'  
HISTCONTROL=ignorespace  
shopt -s histappend  
shopt -s extglob  
HISTSIZE=1000  
HISTFILESIZE=2000  
export HISTIGNORE="!(+(*\ *))"  
PROMPT_COMMAND="hfix; $PROMPT_COMMAND" 

NOTES:

  • Yes, it is complicated... but, it removes all duplicates and yet preserves chronology within each terminal!
  • my HISTIGNORE ignores all commands that don't have arguments. This may not be desireable by some folks and can be left out.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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