Zephyr Shell Commands
Expert guidance on Zephyr's Shell subsystem for creating custom CLI commands, managing subcommands, and interacting with users via console interfaces.
Table of Contents
Core Concepts
Command Registration vs. Handler Implementation
| Step | What | Where |
|---|---|---|
| Define Handler | Implement shell_cmd_handler function |
Your C file |
| Register Command | Use SHELL_CMD_REGISTER or SHELL_CMD_ARG_REGISTER |
Your C file (global scope) |
| Enable Shell | Set CONFIG_SHELL=y |
prj.conf |
Handler Prototype
typedef int (*shell_cmd_handler)(const struct shell *sh, size_t argc, char **argv);
sh: Shell instance pointer (use for all output)argc: Argument count (includes command name)argv: Argument vector.argv[0]is the command name- Return:
0success,-EINVALinvalid args,-ENOEXECexecution failed
Key Rules
- Use shell output functions: Always use
shell_print(),shell_error(), etc. Never useprintk()in handlers - Return codes matter: Return
0on success, negative errno on failure - Argument counting:
mandatorycount includes the command name itself
Common Workflows
1. Creating a Simple Root Command
static int cmd_hello(const struct shell *sh, size_t argc, char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
shell_print(sh, "Hello, World!");
return 0;
}
SHELL_CMD_REGISTER(hello, NULL, "Print hello message", cmd_hello);
2. Creating Commands with Subcommands
- Macro syntax and registration: See macros.md
- Complete examples: See examples.md
Quick Example:
static int cmd_demo_ping(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "pong");
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(sub_demo,
SHELL_CMD(ping, NULL, "Ping command", cmd_demo_ping),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL);
3. Commands with Argument Validation
Use SHELL_CMD_ARG_REGISTER to automatically validate argument counts.
/* Command requires exactly 2 args: command + one parameter */
SHELL_CMD_ARG_REGISTER(greet, NULL, "Greet <name>", cmd_greet, 2, 0);
- Argument parsing techniques: See advanced.md
4. Dynamic Commands
Create commands whose subcommands are determined at runtime.
- Dynamic command creation: See advanced.md
5. Dictionary Commands
Map string subcommands to data values (perfect for enums, settings).
- Dictionary command patterns: See advanced.md
Command Structure
Hierarchy
Root Commands (Level 0)
├── Registered with SHELL_CMD_REGISTER or SHELL_CMD_ARG_REGISTER
├── Stored in dedicated memory section, alphabetically sorted
│
└── Subcommands (Level 1+)
├── Static: SHELL_STATIC_SUBCMD_SET_CREATE
├── Dynamic: SHELL_DYNAMIC_CMD_CREATE
└── Dictionary: SHELL_SUBCMD_DICT_SET_CREATE
Macro Reference
| Macro | Purpose |
|---|---|
SHELL_CMD_REGISTER |
Register root command |
SHELL_CMD_ARG_REGISTER |
Register root command with arg validation |
SHELL_STATIC_SUBCMD_SET_CREATE |
Define static subcommand array |
SHELL_DYNAMIC_CMD_CREATE |
Define dynamic subcommand generator |
SHELL_SUBCMD_DICT_SET_CREATE |
Define dictionary subcommands |
SHELL_CMD |
Define a subcommand entry |
SHELL_CMD_ARG |
Define subcommand with arg validation |
SHELL_COND_CMD |
Conditional subcommand (Kconfig-based) |
- Complete macro documentation: See macros.md
Configuration
Essential Kconfig Options
CONFIG_SHELL=y # Enable shell subsystem
CONFIG_SHELL_BACKEND_SERIAL=y # UART backend (most common)
CONFIG_SHELL_LOG_BACKEND=y # Shell as logging backend
Backend Selection
| Backend | Kconfig | Use Case |
|---|---|---|
| UART | CONFIG_SHELL_BACKEND_SERIAL |
Default, most common |
| USB CDC ACM | Snippet cdc-acm-console |
USB serial |
| RTT | CONFIG_SHELL_BACKEND_RTT |
Segger J-Link debugging |
| Telnet | CONFIG_SHELL_BACKEND_TELNET |
Network access |
| BLE NUS | Snippet nus-console |
Bluetooth LE |
- Kconfig options reference: See kconfig.md
- Backend configuration guide: See backends.md
Troubleshooting
For common errors and debugging techniques:
- See debugging.md
Quick Reference
| Issue | Likely Cause | Fix |
|---|---|---|
| Command not appearing | Not registered or shell disabled | Check SHELL_CMD_REGISTER, enable CONFIG_SHELL |
| Output not visible | Using printk() instead of shell_print() |
Use shell output functions |
| "Wrong parameter count" | Mandatory arg count wrong | Adjust mandatory (includes command name) |
| Handler not called | Arg validation failing | Check mandatory/optional counts |
| Subcommands not showing | Missing SHELL_SUBCMD_SET_END |
Add terminator to subcommand array |
References
- macros.md — Command registration macros, subcommand creation
- api.md — Output functions, helper functions, handler prototypes
- advanced.md — Dynamic commands, dictionary commands, getopt, argument parsing
- kconfig.md — Shell Kconfig options reference
- backends.md — Backend configuration (UART, RTT, USB, Telnet, BLE)
- examples.md — Complete working examples
- debugging.md — Error resolution and debugging techniques