1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
# History
## For Developers
The `cmd` module from the Python standard library includes `readline` history.
[cmd2.Cmd][] offers the same `readline` capabilities, but also maintains its own data structures for
the history of all commands entered by the user. When the class is initialized, it creates an
instance of the [cmd2.history.History][] class (which is a subclass of `list`) as
`cmd2.Cmd.history`.
Each time a command is executed (this gets complex, see
[Command Processing Loop](./hooks.md#command-processing-loop) for exactly when) the parsed
[cmd2.Statement][] is appended to `cmd2.Cmd.history`.
`cmd2` adds the option of making this history persistent via optional arguments to
[cmd2.Cmd.\_\_init\_\_][]. If you pass a filename in the `persistent_history_file` argument, the
contents of `cmd2.Cmd.history` will be written as compressed JSON to that history file. We chose
this format instead of plain text to preserve the complete `cmd2.Statement` object for each command.
!!! note
`readline` saves everything you type, whether it is a valid command or not. `cmd2` only saves input to internal history if the command parses successfully and is a valid command. This design choice was intentional, because the contents of history can be saved to a file as a script, or can be re-run. Not saving invalid input reduces unintentional errors when doing so.
However, this design choice causes an inconsistency between the `readline` history and the `cmd2` history when you enter an invalid command: it is saved to the `readline` history, but not to the `cmd2` history.
The `cmd2.Cmd.history` attribute, the `cmd2.history.History` class, and the
[cmd2.history.HistoryItem][] class are all part of the public API for `cmd2.Cmd`. You could use
these classes to implement your own `history` command (see below for documentation on how the
built-in `history` command works).
## For Users
You can use the :arrow_up: up and :arrow_down: down arrow keys to move through the history of
previously entered commands.
If the `readline` module is installed, you can press `Control-p` to move to the previously entered
command, and `Control-n` to move to the next command. You can also search through the command
history using `Control-r`.
You can refer to the [readline cheat sheet](http://readline.kablamo.org/emacs.html) or you can dig
into the [GNU Readline User Manual](http://man7.org/linux/man-pages/man3/readline.3.html) for all
the details, including instructions for customizing the key bindings.
`cmd2` makes a third type of history access available with the `history` command. Each time the user
enters a command, `cmd2` saves the input. The `history` command lets you do interesting things with
that saved input. The examples to follow all assume that you have entered the following commands:
(Cmd) alias create one !echo one
Alias 'one' created
(Cmd) alias create two !echo two
Alias 'two' created
(Cmd) alias create three !echo three
Alias 'three' created
(Cmd) alias create four !echo four
Alias 'four' created
In its simplest form, the `history` command displays previously entered commands. With no additional
arguments, it displays all previously entered commands:
(Cmd) history
1 alias create one !echo one
2 alias create two !echo two
3 alias create three !echo three
4 alias create four !echo four
If you give a positive integer as an argument, then it only displays the specified command:
(Cmd) history 4
4 alias create four !echo four
If you give a negative integer _N_ as an argument, then it displays the _Nth_ last command. For
example, if you give `-1` it will display the last command you entered. If you give `-2` it will
display the next to last command you entered, and so forth:
(Cmd) history -2
3 alias create three !echo three
You can use a similar mechanism to display a range of commands. Simply give two command numbers
separated by `..` or `:`, and you will see all commands between, and including, those two numbers:
(Cmd) history 1:3
1 alias create one !echo one
2 alias create two !echo two
3 alias create three !echo three
If you omit the first number, it will start at the beginning. If you omit the last number, it will
continue to the end:
(Cmd) history :2
1 alias create one !echo one
2 alias create two !echo two
(Cmd) history 2:
2 alias create two !echo two
3 alias create three !echo three
4 alias create four !echo four
If you want to display the last three commands entered:
(Cmd) history -- -3:
2 alias create two !echo two
3 alias create three !echo three
4 alias create four !echo four
Notice the double dashes. These are required because the history command uses `argparse` to parse
the command line arguments. As described in the
[argparse documentation](https://docs.python.org/3/library/argparse.html) , `-3:` is an option, not
an argument:
> If you have positional arguments that must begin with - and don't look like negative numbers, you
> can insert the pseudo-argument '--' which tells parse[args]{#args}() that everything after that is
> a positional argument:
There is no zeroth command, so don't ask for it. If you are a Python programmer, you've probably
noticed this looks a lot like the slice syntax for lists and arrays. It is, with the exception that
the first history command is 1, where the first element in a Python array is 0.
Besides selecting previous commands by number, you can also search for them. You can use a simple
string search:
(Cmd) history two
2 alias create two !echo two
Or a regular expression search by enclosing your regex in slashes:
(Cmd) history '/te\ +th/'
3 alias create three !echo three
If your regular expression contains any characters that `argparse` finds interesting, like dash or
plus, you also need to enclose your regular expression in quotation marks.
This all sounds great, but doesn't it seem like a bit of overkill to have all these ways to select
commands if all we can do is display them? Turns out, displaying history commands is just the
beginning. The history command can perform many other actions:
- running previously entered commands
- saving previously entered commands to a text file
- opening previously entered commands in your favorite text editor
- running previously entered commands, saving the commands and their output to a text file
- clearing the history of entered commands
Each of these actions is invoked using a command line option. The `-r` or `--run` option runs one or
more previously entered commands. To run command number 1:
(Cmd) history --run 1
To rerun the last two commands (there's that double dash again to make argparse stop looking for
options):
(Cmd) history -r -- -2:
Say you want to re-run some previously entered commands, but you would really like to make a few
changes to them before doing so. When you use the `-e` or `--edit` option, `history` will write the
selected commands out to a text file, and open that file with a text editor. You make whatever
changes, additions, or deletions, you want. When you leave the text editor, all the commands in the
file are executed. To edit and then re-run commands 2-4 you would:
(Cmd) history --edit 2:4
If you want to save the commands to a text file, but not edit and re-run them, use the `-o` or
`--output-file` option. This is a great way to create [Scripts](./scripting.md), which can be
executed using the `run_script` command. To save the first 5 commands entered in this session to a
text file:
(Cmd) history :5 -o history.txt
The `history` command can also save both the commands and their output to a text file. This is
called a transcript. See [Transcripts](./transcripts.md) for more information on how transcripts
work, and what you can use them for. To create a transcript use the `-t` or `--transcription`
option:
(Cmd) history 2:3 --transcript transcript.txt
The `--transcript` option implies `--run`: the commands must be re-run in order to capture their
output to the transcript file.
!!! warning
Unlike the `-o`/`--output-file` option, the `-t`/`--transcript` option will actually run the selected history commands again. This is necessary for creating a transcript file since the history saves the commands themselves but does not save their output. Please note that a side-effect of this is that the commands will appear again at the end of the history.
The last action the history command can perform is to clear the command history using `-c` or
`--clear`:
(Cmd) history -c
In addition to these five actions, the `history` command also has some options to control how the
output is formatted. With no arguments, the `history` command displays the command number before
each command. This is great when displaying history to the screen because it gives you an easy
reference to identify previously entered commands. However, when creating a script or a transcript,
the command numbers would prevent the script from loading properly. The `-s` or `--script` option
instructs the `history` command to suppress the line numbers. This option is automatically set by
the `--output-file`, `--transcript`, and `--edit` options. If you want to output the history
commands with line numbers to a file, you can do it with output redirection:
(Cmd) history 1:4 > history.txt
You might use `-s` or `--script` on its own if you want to display history commands to the screen
without line numbers, so you can copy them to the clipboard:
(Cmd) history -s 1:3
`cmd2` supports both aliases and macros, which allow you to substitute a short, more convenient
input string with a longer replacement string. Say we create an alias like this, and then use it:
(Cmd) alias create ls shell ls -aF
Alias 'ls' created
(Cmd) ls -d h*
history.txt htmlcov/
By default, the `history` command shows exactly what we typed:
(Cmd) history
1 alias create ls shell ls -aF
2 ls -d h*
There are two ways to modify the display so you can see what aliases and macros were expanded to.
The first is to use `-x` or `--expanded`. These options show the expanded command instead of the
entered command:
(Cmd) history -x
1 alias create ls shell ls -aF
2 shell ls -aF -d h*
If you want to see both the entered command and the expanded command, use the `-v` or `--verbose`
option:
(Cmd) history -v
1 alias create ls shell ls -aF
2 ls -d h*
2x shell ls -aF -d h*
If the entered command had no expansion, it is displayed as usual. However, if there is some change
as the result of expanding macros and aliases, then the entered command is displayed with the
number, and the expanded command is displayed with the number followed by an `x`.
|