cmd2 is a tool for building interactive command line applications in Python. Its goal is to make it quick and easy for developers to build feature-rich and user-friendly interactive command line applications. It provides a simple API which is an extension of Python's built-in cmd module. cmd2 provides a wealth of features on top of cmd to make your life easier and eliminates much of the boilerplate code which would be necessary when using cmd.
Click on image below to watch a short video demonstrating the capabilities of cmd2:
- Searchable command history (
history
command and<Ctrl>+r
) - optionally persistent - Text file scripting of your application with
run_script
(@
) and_relative_run_script
(@@
) - Python scripting of your application with
run_pyscript
- Run shell commands with
!
- Pipe command output to shell commands with
|
- Redirect command output to file with
>
,>>
- Bare
>
,>>
with no filename send output to paste buffer (clipboard) py
enters interactive Python console (opt-inipy
for IPython console)- Option to display long output using a pager with
cmd2.Cmd.ppaged()
- Multi-line commands
- Special-character command shortcuts (beyond cmd's
?
and!
) - Command aliasing similar to bash
alias
command - Macros, which are similar to aliases, but they can contain argument placeholders
- Ability to run commands at startup from an initialization script
- Settable environment parameters
- Parsing commands with arguments using
argparse
, including support for subcommands - Unicode character support
- Good tab completion of commands, subcommands, file system paths, and shell commands
- Automatic tab completion of
argparse
flags when using one of thecmd2
argparse
decorators - Support for Python 3.5+ on Windows, macOS, and Linux
- Trivial to provide built-in help for all commands
- Built-in regression testing framework for your applications (transcript-based testing)
- Transcripts for use with built-in regression can be automatically generated from
history -t
orrun_script -t
- Alerts that seamlessly print while user enters text at prompt
- Colored and stylized output using
ansi.style()
cmd2
will end support for Python 3.5 on August 31, 2020. Python 3.5 was released
on Sept. 13, 2015 and its end-of-life is planned for September 2020.
New versions of cmd2
will stop supporting Python 3.5 in a few months. We are very much looking forward to being able to use
features added in Python 3.6 such as f-strings.
On all operating systems, the latest stable version of cmd2
can be installed using pip:
pip install -U cmd2
cmd2 works with Python 3.5+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party dependencies.
For information on other installation options, see Installation Instructions in the cmd2 documentation.
The latest documentation for cmd2 can be read online here: https://cmd2.readthedocs.io/en/latest/
It is available in HTML, PDF, and ePub formats.
Instructions for implementing each feature follow.
-
Extension of the
cmd
module. So capabilities provided bycmd
still exist- Your applicaiton inherits from
cmd2.Cmd
, let's say you call this classMyApp
import cmd2 class MyApp(cmd2.Cmd): pass
- Define a command named foo by creating a method named do_foo
class MyApp(cmd2.Cmd): def do_foo(self, args): """This docstring is the built-in help for the foo command.""" self.poutput(cmd2.style('foo bar baz', fg=cmd2.fg.red))
- By default the docstring for your do_foo method is the help for the foo command
- NOTE: This doesn't apply if you use one of the
argparse
decorators mentioned below
- NOTE: This doesn't apply if you use one of the
- Can provide more custom help by creating a help_foo method (except when using
argparse
decorators) - Can provide custom tab completion for the foo command by creating a complete_foo method
- Easy to upgrade an existing
cmd
app tocmd2
- Run your
cmd2
app using the built-in REPL by executing the cmdloop method
- Your applicaiton inherits from
-
Searchable command history
- Readline history using
<Ctrl>+r
, arrow keys, and other Readline Shortcut keys cmd2
history
command provides flexible and powerful search- If you wish to exclude some of your custom commands from the history, append their names to the list at
Cmd.exclude_from_history
. - Do
help history
in anycmd2
application for more information
- If you wish to exclude some of your custom commands from the history, append their names to the list at
- Both of the above types of history can be optionally persistent between application runs
- Via optional
persistent_history_file
argument tocmd2.Cmd
initializer
- Via optional
- Readline history using
-
Simple scripting using text files with one command + arguments per line
- See the Command Scripts section of the
cmd2
docs for more info - See script.txt for a trivial example script that can be
used in any
cmd2
application with therun_script
command (or@
shortcut)
- See the Command Scripts section of the
-
Powerful and flexible built-in Python scripting of your application using the
run_pyscript
command- Run arbitrary Python scripts within your
cmd2
application with the ability to also call customcmd2
commands - No separate API for your end users to learn
- Syntax for calling
cmd2
commands in arun_pyscript
is essentially identical to what they would enter on the command line
- Syntax for calling
- See the Python Scripts section of the
cmd2
docs for more info - Also see the python_scripting.py example in conjunction with the conditional.py script
- Run arbitrary Python scripts within your
-
Parsing commands with
argparse
- The built-in
cmd2.with_argparser
decorator will parse arguments usingargparse.ArgumentParser
- Optionally,
cmd2.with_argparser(.., with_unknown_args=True)
can be used to pass all unknown arguments as a list
- Optionally,
import argparse from cmd2 import with_argparser argparser = argparse.ArgumentParser() argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') argparser.add_argument('words', nargs='+', help='words to say') @with_argparser(argparser) def do_speak(self, args): """Repeats what you tell me to.""" words = [] for word in args.words: if args.piglatin: word = '%s%say' % (word[1:], word[0]) if args.shout: word = word.upper() words.append(word) self.stdout.write('{}\n'.format(' '.join(words)))
See Argument Processing in the docs for more details
NOTE:
cmd2
also provides theCmd2ArgumentParser
customization ofargparse.ArgumentParser
for prettier formatting of help and error messages. - The built-in
-
cmd2
applications function like a full-featured shell in many ways (and are cross-platform)- Run arbitrary shell commands by preceding them with
!
orshell
- Redirect the output of any command to a file with
>
for overwrite or>>
for append- If no file name provided after the
>
/>>
, then output goes to the clipboard/pastebuffer
- If no file name provided after the
- Pipe the output of any command to an arbitrary shell command with
|
- Create your own custom command aliases using the
alias
command - Create your own custom macros using the
macro
command (similar to aliases, but allow arguments) - Settable environment parameters that users can change during execution supported via
set
command - Option to display long output using a pager with
cmd2.Cmd.ppaged()
- Optionally specify a startup script that end users can use to customize their environment
- Run arbitrary shell commands by preceding them with
-
Top-notch tab completion capabilities which are easy to use but very powerful
- For a command foo implement a complete_foo method to provide custom tab completion for that command
- But the helper methods within
cmd2
discussed below mean you would rarely have to implement this from scratch
- But the helper methods within
- Commands which use one of the
argparse
decorators have automatic tab completion ofargparse
flags- And also provide help hints for values associated with these flags
- Experiment with the argprint.py example using the oprint and pprint commands to get a feel for how this works
basic_complete
helper method for tab completion against a listpath_complete
helper method provides flexible tab completion of file system paths- See the paged_output.py example for a simple use case
- See the python_scripting.py example for a more full-featured use case
delimiter_complete
helper method for tab completion against a list but each match is split on a delimiter- See the basic_completion.py example for a demonstration of how to use this feature
flag_based_complete
helper method for tab completion based on a particular flag preceding the token being completedindex_based_complete
helper method for tab completion based on a fixed position in the input string- See the basic_completion.py example for a demonstration of how to use these features
flag_based_complete()
andindex_based_complete()
are basic methods and should only be used if you are not familiar with argparse. The recommended approach for tab completing positional tokens and flags is to use argparse-based completion
cmd2
in combination withargparse
also provide several advanced capabilities for automatic tab completion- See the argparse_completion.py example for more info
- For a command foo implement a complete_foo method to provide custom tab completion for that command
-
Multi-line commands
Any command accepts multi-line input when its name is listed the
multiline_commands
optional argument tocmd2.Cmd.__init
. The program will keep expecting input until a line ends with any of the characters listed in theterminators
optional argument tocmd2.Cmd.__init__()
. The default terminators are;
and\n
(empty newline). -
Special-character shortcut commands (beyond cmd's "@" and "!")
To create a single-character shortcut for a command, update
Cmd.shortcuts
. -
Asynchronous alerts based on events happening in background threads
cmd2
provides the following helper methods for providing information to users asynchronously even though thecmd2
REPL is a line-oriented command interpreter:async_alert
- display an important message to the user while they are at the prompt in between commands- To the user it appears as if an alert message is printed above the prompt
async_update_prompt
- update the prompt while the user is still typing at it- This is good for alerting the user to system changes dynamically in between commands
set_window_title
- set the terminal window title- This changes the window title of the terminal that the user is running the
cmd2
app within
- This changes the window title of the terminal that the user is running the
- PyOhio 2019 presentation:
Example cmd2 application (examples/example.py):
#!/usr/bin/env python
# coding=utf-8
"""
A sample application for cmd2.
"""
import argparse
import random
import sys
import cmd2
class CmdLineApp(cmd2.Cmd):
""" Example cmd2 application. """
# Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist
# default_to_shell = True
MUMBLES = ['like', '...', 'um', 'er', 'hmmm', 'ahh']
MUMBLE_FIRST = ['so', 'like', 'well']
MUMBLE_LAST = ['right?']
def __init__(self):
self.maxrepeats = 3
shortcuts = dict(cmd2.DEFAULT_SHORTCUTS)
shortcuts.update({'&': 'speak'})
# Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell
super().__init__(use_ipython=False, multiline_commands=['orate'], shortcuts=shortcuts)
# Make maxrepeats settable at runtime
self.add_settable(cmd2.Settable('maxrepeats', int, 'max repetitions for speak command'))
speak_parser = argparse.ArgumentParser()
speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
speak_parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
speak_parser.add_argument('words', nargs='+', help='words to say')
@cmd2.with_argparser(speak_parser)
def do_speak(self, args):
"""Repeats what you tell me to."""
words = []
for word in args.words:
if args.piglatin:
word = '%s%say' % (word[1:], word[0])
if args.shout:
word = word.upper()
words.append(word)
repetitions = args.repeat or 1
for i in range(min(repetitions, self.maxrepeats)):
# .poutput handles newlines, and accommodates output redirection too
self.poutput(' '.join(words))
do_say = do_speak # now "say" is a synonym for "speak"
do_orate = do_speak # another synonym, but this one takes multi-line input
mumble_parser = argparse.ArgumentParser()
mumble_parser.add_argument('-r', '--repeat', type=int, help='how many times to repeat')
mumble_parser.add_argument('words', nargs='+', help='words to say')
@cmd2.with_argparser(mumble_parser)
def do_mumble(self, args):
"""Mumbles what you tell me to."""
repetitions = args.repeat or 1
for i in range(min(repetitions, self.maxrepeats)):
output = []
if (random.random() < .33):
output.append(random.choice(self.MUMBLE_FIRST))
for word in args.words:
if (random.random() < .40):
output.append(random.choice(self.MUMBLES))
output.append(word)
if (random.random() < .25):
output.append(random.choice(self.MUMBLE_LAST))
self.poutput(' '.join(output))
if __name__ == '__main__':
app = CmdLineApp()
sys.exit(app.cmdloop())
The following is a sample session running example.py. Thanks to Cmd2's built-in transcript testing capability, it also serves as a test suite for example.py when saved as transcript_regex.txt. Running
python example.py -t transcript_regex.txt
will run all the commands in the transcript against example.py
, verifying that the output produced
matches the transcript.
example/transcript_regex.txt:
# Run this transcript with "python example.py -t transcript_regex.txt"
# Anything between two forward slashes, /, is interpreted as a regular expression (regex).
# The regex for editor will match whatever program you use.
# regexes on prompts just make the trailing space obvious
(Cmd) set
allow_style: '/(Terminal|Always|Never)/'
always_show_hint: False
debug: False
echo: False
editor: /.*?/
feedback_to_output: False
maxrepeats: 3
quiet: False
timing: False
Regular expressions can be used anywhere within a transcript file simply by enclosing them within forward slashes, /
.
If you think you've found a bug, please first read through the open Issues. If you're confident it's a new bug, go ahead and create a new GitHub issue. Be sure to include as much information as possible so we can reproduce the bug. At a minimum, please state the following:
cmd2
version- Python version
- OS name and version
- What you did to cause the bug to occur
- Include any traceback or error message associated with the bug
Here are a few examples of open-source projects which use cmd2
:
- Jok3r
- Network & Web Pentest Automation Framework
- CephFS Shell
- Ceph is a distributed object, block, and file storage platform
- JSShell
- An interactive multi-user web JavaScript shell
- psiTurk
- An open platform for science on Amazon Mechanical Turk
- Poseidon
- Leverages software-defined networks (SDNs) to acquire and then feed network traffic to a number of machine learning techniques
- Unipacker
- Automatic and platform-independent unpacker for Windows binaries based on emulation
- FLASHMINGO
- Automatic analysis of SWF files based on some heuristics. Extensible via plugins.
- tomcatmanager
- A command line tool and python library for managing a tomcat server
- Expliot
- Internet of Things (IoT) exploitation framework
- mptcpanalyzer
- Tool to help analyze mptcp pcaps
- clanvas
- Command-line client for Canvas by Instructure