You can approximate per-directory history in zsh using plugins or custom hooks. The shell itself doesn’t support this natively (though patches have been proposed). (zsh.org)
Here are viable methods:
Method 1: Use the “per-directory-history” plugin (Oh My Zsh or standalone)
- Oh My Zsh includes a plugin called
per-directory-history. (GitHub) - To enable it, add
per-directory-historyto yourplugins=( … )in~/.zshrc. (Unix & Linux Stack Exchange) - The plugin arranges that commands are saved to both a global history file and to per-directory-history files (mirroring the directory tree under a base history directory). (Jim Hester)
- There is a toggle (default key binding
Ctrl-G) to switch between viewing global history and directory-specific history. (GitHub) - You can configure base dir for per-directory history via a variable like
HISTORY_BASE. (GitHub)
Method 2: Use another plugin or custom “cwd-history” approach
- The plugin zsh-cwd-history stores separate
HISTFILEper directory and uses thechpwdhook to change history file when youcd. (Unix & Linux Stack Exchange) - Another project: ericfreese/zsh-cwd-history (mentioned in StackOverflow answers) (Unix & Linux Stack Exchange)
- You can bind a key to toggle between directory history vs global history in such plugins. (Unix & Linux Stack Exchange)
Method 3: DIY using hooks (zshaddhistory / chpwd)
If you want to roll your own:
-
In your
~/.zshrc, set a base directory to store local histories, e.g.:export DIRHIST_BASE="$HOME/.dirhist" -
Use
chpwdhook (runs on eachcd) to switchHISTFILE:function chpwd_set_histfile() { local dir_rel="${PWD/#$HOME\//}" # directory relative to home local histf="${DIRHIST_BASE}/${dir_rel}/.zsh_history" mkdir -p "$(dirname "$histf")" HISTFILE="$histf" } autoload -U add-zsh-hook add-zsh-hook chpwd chpwd_set_histfile -
Optionally, when starting the shell (at prompt or init), you may want to load the relevant directory history:
if [[ -n $PWD ]]; then chpwd_set_histfile fc -R # read history from the new HISTFILE fi -
You may also want to duplicate commands into a global history file (so you don’t lose cross-dir commands). You can use the
zshaddhistoryfunction to append each new command to a global log as well. Example:function zshaddhistory() { local cmd=${1%%$'\n'} # strip newline print -sr -- "$cmd" # to current HISTFILE print -s -- "$cmd" >> "$HOME/.zsh_global_history" return 1 # prevent double logging by default handler }
Caveats:
- You must manage
HISTSIZE,SAVEHIST, trimming, etc. - If you have concurrent shells in the same directory, they write to the same file.
- Performance may degrade if you have many directories with deep trees.
- Some plugins limit history size per directory.
If you like, I can generate a ready-to-use .zshrc snippet (or plugin setup) for your environment (Linux/macOS). Do you prefer plugin-based or DIY?
Absolutely! Instead of implementing per-directory command history, you can enhance your Zsh experience by integrating fuzzy search for command history. This approach offers several advantages:
Fuzzy Matching: Allows you to recall commands even if you don't remember the exact syntax.
Efficiency: Enables quick searching through your command history, saving time.
Simplicity: Doesn't require complex configurations or additional plugins.
To implement this, you can use the
fzf(fuzzy finder) tool in combination with Zsh's reverse search functionality. Here's how you can set it up:Install
fzf: If you haven't already, installfzfby running:Configure Reverse Search: Add the following to your
~/.zshrcto bindCtrl+Rto anfzf-powered reverse search:This configuration replaces the default reverse search with a more powerful fuzzy search.
Optional - Customize Key Bindings: If you prefer a different key binding, you can modify the
bindkeysettings in your~/.zshrc. For example, to bindCtrl+Sto the reverse search:By following these steps, you'll have a fuzzy search integrated into your Zsh history, allowing for more efficient command recall without the need for per-directory history setups.
Let me know if you need further assistance with this setup!