
Picture by Writer | Ideogram
# Introduction
I’m certain most of you’ve gotten used a command shell sooner or later. In case you haven’t, whereas it might look boring in comparison with a GUI, a command-line interface (CLI) could be very light-weight and provides you rather more management. Some widespread examples are SQLite, Git, and the Python REPL. On this tutorial, we’ll discover ways to use Python’s cmd
module to construct our personal interactive shell with none exterior dependencies. It’s quite simple and intuitive to get began. Engaged on initiatives like this helps you perceive how issues work underneath the hood—belongings you usually use each day however don’t suppose a lot about. It’s additionally helpful in case you ever plan to construct admin consoles in your purposes.
We’ll construct our shell in small chunks, beginning with a minimal instance after which steadily including instructions, assist, fundamental validation, aliases, and pleasant output. The one requirement out of your aspect is to have a fundamental familiarity with Python capabilities and courses. So, let’s get began.
# Step-by-Step Course of to Construct Your Personal Python Shell
Let’s have a fast overview of the cmd
module, since we’ve already used it however haven’t defined what it’s. It offers a base class (cmd.Cmd
) to construct line-oriented command interpreters, which suggests it processes one command at a time. It additionally takes care of studying enter through a immediate, command dispatch (mapping textual content to strategies), and the assistance system. You implement instructions by defining strategies named do_
. The module handles the remainder—simple and easy.
// Step 1: Creating the Minimal Shell
Create a file referred to as myshell.py
:
import cmd
class MyShell(cmd.Cmd):
intro = "Welcome to MyShell! Sort assist or ? to checklist instructions.n"
immediate = "(myshell) "
def do_greet(self, arg):
"""Greet the named individual: greet """
identify = arg.strip() or "stranger"
print(f"Howdy, {identify}!")
def do_exit(self, arg):
"""Exit the shell."""
print("Goodbye!")
return True # Returning True tells cmdloop() to exit
if __name__ == "__main__":
MyShell().cmdloop()
Run the code utilizing:
Now, let’s attempt just a few instructions. cmdloop()
will begin the interactive loop, and we will work together as proven beneath:
Welcome to MyShell! Sort assist or ? to checklist instructions.
(myshell) assist
Documented instructions (sort assist ):
========================================
exit greet assist
(myshell) ?
Documented instructions (sort assist ):
========================================
exit greet assist
(myshell) greet kanwal
Howdy, kanwal!
(myshell) exit
Goodbye!
// Step 2: Parsing Arguments Cleanly
For extra complicated instructions that require a number of enter values—comparable to including or multiplying—you will have one thing to parse areas, quotes, and so forth. For this, we’ll use shlex.cut up
. Let’s check out the instance code:
import cmd
import shlex
class MyShell(cmd.Cmd):
intro = "Welcome to MyShell! Sort assist or ? to checklist instructions.n"
immediate = "(myshell) "
def do_add(self, arg):
"""Add numbers: add 1 2 3"""
attempt:
components = shlex.cut up(arg)
nums = [float(p) for p in parts]
besides ValueError:
print("Error: all arguments should be numbers.")
return
besides Exception as e:
print(f"Parse error: {e}")
return
whole = sum(nums)
print(f"Sum = {whole}")
def do_exit(self, arg):
"""Exit the shell."""
print("Goodbye!")
return True
if __name__ == "__main__":
MyShell().cmdloop()
Now, let’s give it a attempt:
Welcome to MyShell! Sort assist or ? to checklist instructions.
(myshell) ?
Documented instructions (sort assist ):
========================================
add exit assist
(myshell) add 2450 3456 8904 3467
Sum = 18277.0
(myshell) exit
Goodbye!
// Step 3: Including a Assist System
We have now already seen one assist command above. That’s the default one which the cmd
module creates robotically. It reveals the strategy docstrings. You can even add customized assist for a command or subject like this:
class MyShell(cmd.Cmd):
intro = "Welcome to MyShell! Sort assist or ? to checklist instructions.n"
immediate = "(myshell) "
def do_greet(self, arg):
"""Greet somebody. Utilization: greet """
identify = arg.strip() or "stranger"
print(f"Howdy, {identify}!")
def help_greet(self):
print("greet ")
print(" Prints a pleasant greeting.")
print(" Instance: greet Alice")
def do_exit(self, arg):
"""Exit the shell."""
print("Goodbye!")
return True
def do_help(self, arg):
# Preserve default conduct, however present a tiny information when no arg
if arg:
return tremendous().do_help(arg)
tremendous().do_help(arg)
print()
print("Fundamentals:")
print(" - Use 'assist' or '?' to checklist instructions.")
print(" - Use 'assist ' for particulars.")
print(" - Arguments help quotes (through shlex).")
Welcome to MyShell! Sort assist or ? to checklist instructions.
(myshell) assist
Documented instructions (sort assist ):
========================================
exit greet
Undocumented instructions:
======================
assist
Fundamentals:
- Use 'assist' or '?' to checklist instructions.
- Use 'assist ' for particulars.
- Arguments help quotes (through shlex).
(myshell) assist greet
greet
Prints a pleasant greeting.
Instance: greet Alice
(myshell) assist exit
Exit the shell.
(myshell) exit
Goodbye!
// Step 4: Dealing with Errors and Unknown Instructions
We are able to override the default()
methodology to intercept unknown instructions. You can even use emptyline()
to regulate what occurs when the consumer presses Enter with no enter. Let’s make the shell do nothing if no enter has been entered:
class MyShell(cmd.Cmd):
immediate = "(myshell) "
def default(self, line):
print(f"Unknown command: {line!r}. Sort 'assist' to checklist instructions.")
def emptyline(self):
# By default, urgent Enter repeats the final command. Override to do nothing.
cross
def do_exit(self, arg):
"""Exit the shell."""
print("Goodbye!")
return True
(myshell) assist
Documented instructions (sort assist ):
========================================
exit assist
(myshell)
(myshell)
(myshell) exit
Goodbye!
// Step 5: Including Command Aliases
Aliases are quick names. Tons of my pals have aliases as effectively, particularly these with the identical names. Equally, you need to use a shorter—and simpler to recollect—model of instructions by implementing aliases within the precmd()
methodology. Right here’s how you are able to do this:
import shlex
import cmd
class MyShell(cmd.Cmd):
immediate = "(myshell) "
aliases = {
"give up": "exit",
"q": "exit",
"whats up": "greet",
"sum": "add",
}
def precmd(self, line: str) -> str:
# Normalize/therapeutic massage enter earlier than dispatch
components = line.strip().cut up(maxsplit=1)
if not components:
return line
cmd_name = components[0]
relaxation = components[1] if len(components) > 1 else ""
if cmd_name in self.aliases:
cmd_name = self.aliases[cmd_name]
return f"{cmd_name} {relaxation}".strip()
# Outline instructions used above
def do_greet(self, arg):
"""Greet somebody. Utilization: greet """
identify = arg.strip() or "stranger"
print(f"Howdy, {identify}!")
def do_add(self, arg):
"""Add numbers: add 1 2 3"""
attempt:
nums = [float(x) for x in shlex.split(arg)]
besides Exception:
print("Utilization: add [ ...]")
return
print(f"Sum = {sum(nums)}")
def do_exit(self, arg):
"""Exit the shell."""
print("Goodbye!")
return True
(myshell) ?
Documented instructions (sort assist ):
========================================
add exit greet assist
(myshell) sum 2 3 4
Sum = 9.0
(myshell) add 2 3 4
Sum = 9.0
(myshell) q
Goodbye!
// Step 6: Placing It All Collectively
import cmd
import shlex
class MyShell(cmd.Cmd):
intro = "Welcome to MyShell! Sort assist or ? to checklist instructions."
immediate = "(myshell) "
# Easy aliases
aliases = {"q": "exit", "give up": "exit", "whats up": "greet", "sum": "add"}
# ----- Enter processing -----
def precmd(self, line):
components = line.strip().cut up(maxsplit=1)
if not components:
return line
cmd_name = components[0]
relaxation = components[1] if len(components) > 1 else ""
if cmd_name in self.aliases:
cmd_name = self.aliases[cmd_name]
return f"{cmd_name} {relaxation}".strip()
def emptyline(self):
# Do nothing on empty line
cross
def default(self, line):
print(f"Unknown command: {line!r}. Sort 'assist' to checklist instructions.")
# ----- Instructions -----
def do_greet(self, arg):
"""Greet somebody. Utilization: greet """
identify = arg.strip() or "stranger"
print(f"Howdy, {identify}!")
def help_greet(self):
print("greet ")
print(" Prints a pleasant greeting.")
print(" Instance: greet Alice")
def do_add(self, arg):
"""Add numbers: add 1 2 3"""
attempt:
nums = [float(x) for x in shlex.split(arg)]
besides Exception:
print("Utilization: add [ ...]")
return
print(f"Sum = {sum(nums)}")
def do_echo(self, arg):
"""Echo again what you sort: echo """
print(arg)
def do_exit(self, arg):
"""Exit the shell."""
print("Goodbye!")
return True
# ----- Assist tweaks -----
def do_help(self, arg):
if arg:
return tremendous().do_help(arg)
tremendous().do_help(arg)
print()
print("Fundamentals:")
print(" - Use 'assist' or '?' to checklist instructions.")
print(" - Use 'assist ' for particulars.")
print(' - Quotes are supported in arguments (e.g., add "3.5" 2).')
if __name__ == "__main__":
MyShell().cmdloop()
Welcome to MyShell! Sort assist or ? to checklist instructions.
(myshell) whats up
Howdy, stranger!
(myshell) WRONG COMMAND
Unknown command: 'WRONG COMMAND'. Sort 'assist' to checklist instructions.
(myshell) echo KDnuggets is a superb web site
KDnuggets is a superb web site
(myshell) exit
Goodbye!
# Wrapping Up
You simply realized the right way to construct an interactive shell utilizing the cmd
module with none exterior dependencies. Isn’t that tremendous?
Earlier than we end, it’s price mentioning just a few widespread pitfalls to be careful for: First, forgetting to return True
in your exit command will forestall the shell loop from ending. Second, counting on easy whitespace splitting for arguments may cause issues when customers enter quoted textual content, so utilizing shlex
is advisable. Lastly, not dealing with the emptyline()
methodology correctly can result in sudden conduct, like repeating the final command when the consumer presses Enter on an empty line.
I might love to listen to your ideas about this text within the feedback part, in addition to any concepts you may wish to discover additional.
Kanwal Mehreen is a machine studying engineer and a technical author with a profound ardour for information science and the intersection of AI with medication. She co-authored the e-book “Maximizing Productiveness with ChatGPT”. As a Google Era Scholar 2022 for APAC, she champions variety and educational excellence. She’s additionally acknowledged as a Teradata Range in Tech Scholar, Mitacs Globalink Analysis Scholar, and Harvard WeCode Scholar. Kanwal is an ardent advocate for change, having based FEMCodes to empower ladies in STEM fields.