top | item 33186412

Fixing macOS Zsh Terminal History Settings

132 points| ackatz | 3 years ago |blog.akatz.org | reply

64 comments

order
[+] saagarjha|3 years ago|reply
This is zsh specific, but here's something I've been burned by enough times that I specifically wanted to mention it: save your history in a file other than the default one. Why? Because if you increase the history limit, and your profile isn't sourced for any reason, the shell will read your history file and use the default history size, clobbering everything that's there. If you use a non-default history file this rogue shell (missing your settings) will dump its history into the default file and leave your custom file untouched.
[+] misnome|3 years ago|reply
I got burned a couple of times in the past with bash-history, and go a small step beyond this, even on zsh, and added to .zshrc:

    preexec_custom_history() {
      echo "$HOSTNAME $$ $(date "+%Y-%m-%dT%H:%M:%S%z") $1" >> "~/.fullhistory"
    }
    preexec_functions+=(preexec_custom_history)
I work on a lot of shared-filesystem computers, and so it's useful to be able to filter for commands ~year ago when I know what computer I was on when I ran it. I have a fzf binding to search through this with ctrl-r, and it's otherwise easily greppable.

When I was still using bash, I had this same thing using https://github.com/rcaloras/bash-preexec .

[+] MawKKe|3 years ago|reply
Also I don't understand why modern shells are so conservative about the defaults. I understand that if a single history file is large, it might slow down shell startup and operation, but at the very least shells could/should do periodic history file rotation. It's very very very unlikely that the history files will be eating all the disk space.
[+] barosl|3 years ago|reply
I also learned the lesson to use a different history file recently. I added `HISTSIZE=-1` to `~/.bashrc` to make the number of items stored in the history unlimited, but the history kept being truncated. The problem was that Ubuntu's default `~/.bashrc` file set `HISTSIZE` at the beginning of the file, and it had a side effect of truncating the history immediately. I had tried various methods but in the end, using a different history file felt the cleanest.
[+] arno_v|3 years ago|reply
I will try this, recently mine got truncated (don't know why) and it's super annoying.
[+] matthberg|3 years ago|reply
I often have multiple concurrent sessions of terminal open, which leads to messed up history interactions. One solution I've encountered (but have not tested yet) is zsh-histdb [0]. It stores sessions' history to a SQLite db instead of a single appended file, with extra metadata about when commands were run, what session, etc. If you've already got your .zshrc file open to mess with the history settings it might be worth checking out that tool while you're at it.

0: https://github.com/larkery/zsh-histdb

[+] skissane|3 years ago|reply
Storing history in SQLite is such a wonderful idea, I wonder why someone doesn’t just add it to readline/libedit/etc, then all apps (which use those libraries) can do it.

Although, I wonder if that might cause problems, if apps already link to SQLite and they might expect a different version, or if unstable apps might cause concurrency/corruption/etc issues with a shared per-user history DB. To avoid all that, maybe a per-user history daemon with a Unix domain socket?

[+] zipperhead|3 years ago|reply
I'd given up on shared history because it never worked the way I like. This looks very promising, thank you.
[+] pilif|3 years ago|reply
if we're talking about zsh history settings, I also recommend

setopt SHARE_HISTORY HIST_IGNORE_DUPS

SHARE_HISTORY will cause zsh to write to the history file after every command which means that two shells running in parallel won't override changes of each other and it will write a timestamp to the file too in order to have the history in chronological order even in light of multiple instances.

HIST_IGNORE_DUPS (or HIST_IGNORE_ALL_DUPS) will cause duplicated commands to not be written to the history file which helps with `Ctrl-R`ing

[+] bckr|3 years ago|reply
Oh! I came here to comment that this was the fix I needed: "When I have 2 shells open and close 1, the next shell I open seems to randomly choose which shell's commands to remember."

Looks like this may be what I need!

[+] dreamcompiler|3 years ago|reply
OT but the first command I type on a new install of MacOS is

  $ chsh -s /bin/bash
because I have 20 years worth of bash scripts that I've carefully tailored to work on bash in MacOS and Linux and I don't have time to rewrite them all just because Apple decided they don't like GPLv3.
[+] msbarnett|3 years ago|reply
Before they changed the default the first command I had to type on a new install was

    $ chsh -s /bin/zsh 
You can’t please everybody.
[+] jmmv|3 years ago|reply
To each their own, but know that you are stuck with a really old version of bash if you do that, and it has some “interesting” bugs in it.

See something I wrote a little while ago on this topic: https://jmmv.dev/2019/11/macos-bash-baggage.html

[+] yjftsjthsd-h|3 years ago|reply
? Don't you just make the scripts start with `#!/user/bin/env bash`? Or do you mean aliases/functions?
[+] kotlin2|3 years ago|reply
You could still use those scripts with a shebang, no?
[+] sneak|3 years ago|reply
I haven’t personally found any system bash scripts that don’t work on system zsh, but I don’t use many bash features because the macOS system bash was so old and outdated. YMMV of course.
[+] joombaga|3 years ago|reply
It's still bash 3 though, right? You're okay with that? I tend to install the newest from brew.
[+] computerfriend|3 years ago|reply
You can still run Bash from Zsh. Your terminal shell is irrelevant.
[+] thakoppno|3 years ago|reply
doesn’t mac show a bash deprecation warning or something else that’s obnoxious when you do that?

  export BASH_SILENCE_DEPRECATION_WARNING=1
[+] commandersaki|3 years ago|reply
I recommend not changing the default shell, but rather having Terminal.app (or whatever) start the shell of your choice (in my case: /opt/local/bin/bash). You can't trust that the files in /opt/local or /usr/local will always be there, whereas the ones bundled by macos will.
[+] revscat|3 years ago|reply
I I do not do this because I have 20 years of zsh scripts.

Also, I like zsh better.

[+] WhyNotHugo|3 years ago|reply
That changes your default shell, bash scripts (which should have the sheband `#!/usr/bin/env bash` will still get executed by bash normally.
[+] greyw|3 years ago|reply
Especially annoying if you have scripts that are meant to be sourced by the shell i.e. the shebang doesn't help you.
[+] sdrothrock|3 years ago|reply
> If you have a shell open and echo "test", then history | grep echo, it will return something like: 891 echo "test".

>

> However, if you issue 16 more unique commands, history | grep echo will no longer be able to find your 891 echo "test" entry.

On zsh, history only returns the last 16 commands, which is the default. But if you type `history 0`, it will return all commands since the zeroth index.

So if I want to search my entire history for instances of a command like this example, I don't modify anything, but just type `history 0 | grep echo` and that does what the author seems to be expecting.

[+] Scarbutt|3 years ago|reply
Does someone knows of some config to make zsh behave similar to bash for interactive use?
[+] opk|3 years ago|reply
Many things are similar. What differences bother a particular user will vary. In many cases, zsh's approach is better so the value of crippling it is questionable. A common example is not splitting variables at spaces which is much better if you might have filenames with spaces in but it helps if you bother to learn to use arrays. Another example is the behaviour when wildcards don't match any files. Bash leaves the word unchanged with the wildcards in place which is less robust and fairly nasty but if you're inclined to be lazy can save on quoting.

So don't try to make zsh mimic bash, use it as-is and whenever something bothers you, try to understand both how the behaviour can be changed and consider the actual merit of the options.

[+] computerfriend|3 years ago|reply
I guess you'll have to elaborate on "similar". What are the differences that you want to resolve? I followed Apple's migration to Zsh and configured it to be Bash-like, at least enough for me to not notice the difference.
[+] bhaak|3 years ago|reply
I guess zsh is better at handling command histories of several concurrent shells than bash?

But still, you can do better. I'm using a snippet from this page: https://spin.atomicobject.com/2016/05/28/log-bash-history/

export PROMPT_COMMAND='if [ "$(id -u)" -ne 0 ]; then echo "$(date "+%Y-%m-%d %H:%M:%S") $(pwd) $(HISTTIMEFORMAT= history 1)" >> ~/.logs/bash-history-$(date "+%Y-%m-%d").log; fi'

This give an easily greppable shell history. An entry looks like this:

2022-10-13 09:14:54 /home/bhaak 1000 vim ~/.bashrc

[+] dolmen|3 years ago|reply
Default settings on Monterey:

    $ grep -i HIST /etc/zshrc 
    # Save command history
    HISTFILE=${ZDOTDIR:-$HOME}/.zsh_history
    HISTSIZE=2000
    SAVEHIST=1000
[+] Normille|3 years ago|reply
I just tried this:

  >echo bollox
  >history | grep bollox
and got a long line of results, dating back to 2019 [Who knew I swore so often in my terminal!]

I don't have any of the fixes suggested in the article in my .zshrc so either it's duff info or not all OSX zsh installs are setup the same. Mind you, I'm still running OSX Mavericks so my zsh may not even have come bundled as the default shell. I may have enabled or installed it myself at a later date.

[+] kuschkufan|3 years ago|reply
Well HISTFILESIZE is not a valid zsh variable, afaik. But the others are and they work fine. That alias does nothing besides listing history since the beginning, though it misses the first entry and should be "history 0".
[+] otikik|3 years ago|reply
Doesn’t it do something weird with the sessions/tabs as well? You write a command in one session, change to another session, grep for it and nothing gets found
[+] serpix|3 years ago|reply
Installed McFly and the history has not once been erased. Prior to that my history keeps getting truncated.