MacOS Catalina terminal tab doesn't remember its own previous commands

I upgraded from El Capitan to Catalina recently; when I click in any terminal tab it used to toggle previous commands executed within that specific tab only, but now it will show commands for all tabs which is very annoying

Is there any setting to fix that?


Solution 1:

Your question regards how the shell maintains its command history. In switching from El Capitan, to Catalina, you may have also switched your default shell from bash to zsh, and these shells have different defaults for maintaining their command history. This answer assumes your question is for altering the behavior of the zsh command history.

You have at least two choices:

  1. Restore bash as your shell:

    % chsh -s /bin/bash
    

    This is easily changed if you decide to return to zsh:

    chsh -s /bin/zsh
    
  2. Configure zsh to disable the "aggregation" of command histories see APPEND_HISTORY

    From man zshoptions:

    APPEND_HISTORY
    If this is set, zsh sessions will append their history list to the history file, rather than replace it. Thus, multiple parallel zsh sessions will all have the new entries from their history lists added to the history file, in the order that they exit. The file will still be periodically re-written to trim it when the number of lines grows 20% beyond the value specified by $SAVEHIST (see also the HIST_SAVE_BY_COPY option).

    Accordingly, if you wish to continue using zsh as your shell, you can un-set the APPEND_HISTORY option, and the command histories from your various terminals/shells will not be aggregated into a single history.

    You can check to see which options are set or unset as follows:

    % setopt
    ...
    # lists options that are set
    
    % unsetopt
    ...
    # lists options that are unset
    
    % set -o
    ...
    # lists all options w/ off/on status 
    

    NOTE: setopt only prints the options not enabled by default. The APPEND_HISTORY option is set by default - as designated by the <D> seen in the man page excerpt above.

    Now, this is a bit obtuse (IMO at least), but notice that there is an option appearing in the unsetopt output named noappendhistory. This is explained in the zsh Options documentation as follows:

    In the following list, options set by default in all emulations are marked ; those set by default only in csh, ksh, sh, or zsh emulations are marked , , , as appropriate. When listing options (by ‘setopt’, ‘unsetopt’, ‘set -o’ or ‘set +o’), those turned on by default appear in the list prefixed with ‘no’. Hence (unless KSH_OPTION_PRINT is set), ‘setopt’ shows all options whose settings are changed from the default.

    (emphasis mine)

    It comes down to this: the option to give you the behavior you want is set as follows:

    setopt noappendhistory
    

    Add this command to your ~/.zshrc file using your favorite editor. Once you've done that, source this file as follows:

    % . ~/.zshrc 
    -- OR --
    % source ~/.zshrc
    

Solution 2:

This answer assumes the question concerns the behavior of the command history function in zsh.

I feel two points should be made before proposing an answer:

  1. Information available online for zsh often refers to a "default configuration". As far as macOS is concerned, the zsh "default configuration" may differ from that described in other sources. The "macOS default configuration" is the zsh "default configuration" as modified by /etc/zshrc. It's best to review this file before making changes, AND all changes should be made in the local user's ~/.zshrc file.
  2. It helps (me at least) to understand that the shell can maintain two (2) command histories. One is a history file (by default: ~/.zsh_history), the other one is a session history that is cached or retained in memory for each session. The parameters SAVEHIST and HISTSIZE determine the depth of the history file, and the session history, respectively. This can be confusing, and the figure below, while not technically accurate, may help in understanding the concept.

For each session, there is a unique session history. However, there is (by default) only one file history for all sessions. Under the macOS default configuration (ref. /etc/zshrc): HISTSIZE=2000, SAVEHIST=1000. When a new session is started, the session history is empty. However, assuming the file history is not empty, pressing the up arrow key (⬆︎) will reveal commands issued from other sessions. As time goes on - as commands are issued in this new session - its session history will begin filling commands entered in this new session. After, say, 20 commands have been issued, the up arrow (⬆︎) will reveal those 20 commands; the next up arrow key press will reveal the latest entry in the file history.

enter image description here

In summary: In a new session under the macOS default configuration (HISTSIZE=2000, SAVEHIST=1000) your command history is drawn from the history file, which is to say from the session histories of other sessions. As more commands are issued in this new session, these session commands will "push" commands from the history file further down in the stack.

As I understand your question, you do not wish your session histories to co-mingle. That is, for any session, you do not want to see any command history from another session - from the history file. After reading the above, if this is the behavior you want, here is one way to do that:

Proposed Answer: Set SAVEHIST=0 and HISTSIZE=2000

Open the file ~/.zshrc in your editor, and add the following two lines which override the macOS defaults:

SAVEHIST=0
HISTSIZE=2000

SAVEHIST=0 will prevent any session from saving its history to the history file. Each session will have a command history consisting only of its unique session history. The up and down arrow keys (⬆︎, ⬇︎) will never show a command from another session because as far as the current session is concerned, that history does not exist. Potentially undesirable side effects of this option are:

  • new sessions have no command history

  • if a session is closed or terminates, command history is lost, but see Note 4 below.

If you tend to keep sessions open for long periods of time (as I do), you could set HISTSIZE to a larger value to postpone "pruning" when the history reaches 120% of its allocation (2,400 commands in this case).

If you wish to retain the history file,zsh provides a large number of options for controlling how the history file and session history are maintained, and how they interact with each other to present your command history. In addition the fc commands are shell built-ins that allow manipulation of the the command history (see also: 1, 2, 3). Beyond the options native to zsh are numerous 3rd party tools dedicated to the command history function - even a tool that stores command history and related tidbits in a relational database. I would summarize by saying, "The shell command history suffers from an embarrassment of riches."


Notes:

  1. Note that the name ~/.zsh_history is not a standard for zsh - it is simply the filename that Apple has chosen.

  2. Apple defines their defaults for zsh in the file /etc/zshrc. It's instructive to review these, but it's probably best to make changes to the defaults within your local configuration file at ~/.zshrc.

  3. HISTFILE, HISTSIZE and SAVEHIST are covered in the zshparam manuals

    HISTFILE (from man 1 zshparam) The file to save the history in when an interactive shell exits. If unset, the history is not saved.

    HISTSIZE (from man zshparam) The maximum number of events stored in the internal history list.

    SAVEHIST (from man zshparam) The maximum number of history events to save in the history file.

  4. The fc commands are shell built-ins that allow manipulation of the the command history (see also: 1, 2, 3).