Skip to content

Latest commit

 

History

History
178 lines (103 loc) · 11.5 KB

CommandHistoryIntro-zsh.md

File metadata and controls

178 lines (103 loc) · 11.5 KB

Using command history in your shell - zsh

This is written from the perspective of a macOS user; specifically, a macOS Catalina (or later) user. Under macOS Catalina, Apple changed the default shell from bash to zsh. However, most of the material here is completely relevant for bash users as well. Some of the semantics will change, but the operation of the shell history is the same for bash and zsh.

What is the command history?

If you open a terminal - for example Terminal.app in macOS - and you enter a command at the prompt, that command is saved into the command history. In fact, depending upon how command history is configured on your machine, every command you have ever issued could be saved into a command history. Control and maintenance of the command history is a function of the shell being used. Different shells manage the command history in different ways, though they also have much in common. If you switch between shells, your command history will be contained in different memory locations and different files.

The command history is useful because we often use the same - or similar - commands repeatedly. These commands may contain long lists of arguments and options that are highly specific, and often arcane. Considerable time and effort may be invested in getting a particular command "tweaked" to perform a certain function in a very specific way. The utility of a command history will be obvious to anyone after using rsync or ffmpeg or git for a while.

How does one begin using history?

The reader is now hopefully motivated, and asking, "How do I access my command history?" As with many things, there are many means to access the command history. Let's start with one of the simplest - history. The obligatory man page:

% man history

unfortunately does not reveal much that is helpful. The history command is built in to the shell - as are many other commands:

Image for post

As it turns out, the history command is useful for listing the command history, but not particularly helpful at finding the command of interest. Nevertheless, as we shall see, it does come in handy, and it's simple to use. The examples below illustrate some uses for the history command. Feel free to try them & return here afterward.

Simpler still is using the up (⬆︎) and down (⬇︎) arrows on the keyboard to scroll up and down in the command history. This is easily demonstrated in any active terminal window - each press of an up or down arrow button will advance or return one command further into the command history stack. Like the history command, this is useful, but not particularly efficient for older commands (further up in the stack) - or for those using the CLI frequently.

Before discussing other methods for accessing the command history, let's briefly focus on how the shell maintains the command history, and by what means the user may exercise control and express his preferences.

As mentioned above, the command history is a function of the shell, and for purposes of this recipe the shell of interest is zsh - currently the default shell in macOS. The file /etc/zshrc contains your machine’s default settings, including a few relevant to the command history. Following are the defaults as of this writing:

% less /etc/zshrc   # peruse the default settings for zsh
...
# Save command history
HISTFILE=${ZDOTDIR:-$HOME}/.zsh_history
HISTSIZE=2000
SAVEHIST=1000
...

Let's briefly review these variables:

  • HISTSIZE declares the size of the session history; session as in an instance of the shell
  • SAVEHIST defines the size of the history file
  • HISTFILE simply declares the name of the user's history file, and where it's stored.

Note that the command history is made up of two separate entities: the session history and the history file. They are "linked" and inter-operate in the following fashion:

  • when a zsh session is closed, the session history is concatenated to the history file
  • when the session history reaches its limit, the overflow is concatenated to the history file
  • when you go beyond the oldest command in the session history, you transition to the history file
  • the command history of a new session, before any commands are issued, is entirely from the history file
  • commands in the session history are unique to that session; the history file contains command history from (potentially) all sessions, past and present.

The following graphic attempts to illustrate some of the relationships between the session histories (one per session), and the history file:

commandhistory2

If you've been using zsh for a while, you can open your command history file at ~/.zsh_history and see what it contains. Likewise, with this file open and in view, the operation and interaction of the session history and the history file may be directly observed. (You may want to temporarily reduce HISTSIZE and SAVEHIST to save time before doing so. Backing up your .zsh_history` may also be warranted.)

Given the above, it is left as an exercise for the reader to determine the logic behind Apple's default settings for HISTSIZE and SAVEHIST in /etc/zshrc. That is to say, the deep thinking that went into setting SAVEHIST to one-half the size of HISTSIZE. Extra points to the reader who shares this revelation!

Some may be tempted to make changes to the default values of SAVEHIST and HISTSIZE. If you wish to make changes, please note:

NOTE: When changing values of HISTSIZE or SAVEHIST, heed the instructions in /etc/zshrc:

# Setup user specific overrides for this in ~/.zshrc

At one time, Apple included this warning in /etc/zshrc: Do not make changes in /etc/zshrc

I have yet to see (as of Ventura) Apple include any practical history settings in ~/.zshrc; consequently, you must do this yourself. You should refer to man zshoptions (specifically the "History" section) when making these changes. Also note that in man zshoptions, it is not always crystal clear whether they are referring to session history - or the history file.

With relationships between the command history components made clear, let us explore some additional methods for accessing the command history:

  1. up (⬆︎) and down (⬇︎) arrows on the keyboard scroll sequentially through the command history 2. the history command and its options will list selected commands 3. controlr at the command prompt will search & match items in your command history
    4. !! runs the previous command; e.g. sudo !! executes the previous command with root privileges

These tools, coupled with an understanding of the command history components and how they interact is enough to begin using the command history productively. A few examples follow with more details.

Examples for accessing command history

1. controlr

Enter controlr at the command line to see the bck-i-search: prompt for a search term:

% 
bck-i-search: _

Assume you need to find the command for an ssh connection; enter ssh as the search term:

% ssh [email protected]   # <-- a finding from command history
bck-i-search: ssh_ 

This is the most recent entry in the command history. If this is NOT the host/command you're searching for, simply enter controlr again to go to the next previous command. Continue controlr until the command/host of interest is found. When found, use the right arrow (➡︎) to select that command and end the search. This will place the selected command on the command line where it may be edited or executed (return). Use controlg to terminate the search & return to a blank command line.

2. history command

Simply running the command history from the CLI lists the 16 most recent commands in the command history. No idea why 16 is the "magic number" here... If you know the location of a particular command in the command history, that may be specified as an argument. This is rarely useful, except perhaps to list all commands; i.e. history 1 - or more likely history 1 | less. Perhaps slightly more useful is piping the entire history 1 output to grep:

% history 1 | grep ssh 

# --OR--

% history 1 | grep ssh | less

These are only two examples. The REFERENCES below may provide more advanced methods for searching the command history more efficiently.


REFERENCES:

  1. Better command history browsing in Terminal - get history-search-forward setup using ~/.profile
  2. Better zsh History
  3. A Guide to ZSH History
  4. A SO Q&A to get history-search-forward using bind in ~/.zshrc
  5. Q&A: How can I search history with text already entered at the prompt in zsh?
  6. Docs: zsh Line Editor's History Control ; see also ZLE Builtins
  7. Lorna Jane's blog on 'Navigating Bash History with Ctrl+R'
  8. How To Set Up History-Based Autocompletion in Zsh