doc/services/shell/index.rst
.. _shell_api:
Shell
.. contents:: :local: :depth: 2
Overview
This module allows you to create and handle a shell with a user-defined command set. You can use it in examples where more than simple button or LED user interaction is required. This module is a Unix-like shell with these features:
logging_api.Tab key.clear, :command:shell, :command:colors,
:command:echo, :command:history and :command:resize.↑ :kbd:↓ or meta keys.←, :kbd:→, :kbd:Backspace,
:kbd:Delete, :kbd:End, :kbd:Home, :kbd:Insert.VT100 and ESC[n~ for cursor control
and color printing.* and ?... note::
Some of these features have a significant impact on RAM and flash usage,
but many can be disabled when not needed. To default to options which
favor reduced RAM and flash requirements instead of features, you should
enable :kconfig:option:CONFIG_SHELL_MINIMAL and selectively enable just the
features you want.
.. _backends:
Backends
The module can be connected to any transport for command input and output. At this point, the following transport layers are implemented:
Enabling :kconfig:option:CONFIG_SHELL_BACKEND_TELNET will allow users to use telnet
as a shell backend. Connecting to it can be done using PuTTY or any telnet client.
For example:
.. code-block:: none
telnet <ip address> <port>
By default the telnet client won't handle telnet commands and configuration. Although
command support can be enabled with :kconfig:option:CONFIG_SHELL_TELNET_SUPPORT_COMMAND.
This will give the telnet client access to a very limited set of supported commands but
still can be turned on if needed. One of the command options it supports is the ECHO
option. This will allow the client to be in character mode (character at a time),
similar to a UART backend in that regard. This will make the client send a character
as soon as it is typed having the effect of increasing the network traffic
considerably. For that cost, it will enable the line editing,
tab completion <tab-feature_>, and history <history-feature_>
features of the shell.
To configure Shell USB CDC ACM backend, simply add the snippet cdc-acm-console
to your build:
.. code-block:: console
west build -S cdc-acm-console [...]
Details on the configuration settings are captured in the following files:
snippets/cdc-acm-console/cdc-acm-console.conf.snippets/cdc-acm-console/cdc-acm-console.overlay.To configure Bluetooth LE (NUS) backend, simply add the snippet nus-console
to your build:
.. code-block:: console
west build -S nus-console [...]
Details on the configuration settings are captured in the following files:
snippets/nus-console/nus-console.conf.snippets/nus-console/nus-console.overlay.To configure Segger RTT backend, add the following configurations to your build:
CONFIG_USE_SEGGER_RTTCONFIG_SHELL_BACKEND_RTTCONFIG_SHELL_BACKEND_SERIALDetails on additional configuration settings are captured in:
:zephyr_file:samples/subsys/shell/shell_module/prj_minimal_rtt.conf.
.. _shell_rtt_west:
Attach to and configure RTT with:
.. code-block:: console
$ west rtt
.. note::
If your default runner does not have support for RTT, check your board's documentation page for
any other runners that support RTT. You may then use the --runner option to specify a
different runner.
.. code-block:: console
$ west rtt --runner <runner>
.. _shell_rtt_putty:
Use following procedure:
Open debug session and continue running the application.
.. code-block:: none
west attach
Open PuTTY. Use telnet port 19021 and specific Terminal configuration. Set Local echo
to Force off and Local line editing to Force off (see image below).
.. image:: images/putty_rtt.png :align: center :alt: RTT PuTTY terminal configuration.
On macOS JLinkRTTClient won't let you enter input. Instead, please use following procedure:
Open up a first Terminal window and enter:
.. code-block:: none
JLinkRTTLogger -Device NRF52840_XXAA -RTTChannel 1 -if SWD -Speed 4000 ~/rtt.log
(change device if required)
Open up a second Terminal window and enter:
.. code-block:: none
nc localhost 19021
Now you should have a network connection to RTT that will let you enter input
to the shell. However, contrary to PuTTY <shell_rtt_putty_>_ some features like
Tab completion do not work.
Commands
Shell commands are organized in a tree structure and grouped into the following types:
The following list is a set of useful command groups and how to enable them:
CONFIG_GPIOCONFIG_GPIO_SHELLCONFIG_I2CCONFIG_I2C_SHELLCONFIG_SENSORCONFIG_SENSOR_SHELLCONFIG_FLASHCONFIG_FLASH_SHELLCONFIG_FILE_SYSTEMCONFIG_FILE_SYSTEM_SHELLCONFIG_ADCCONFIG_ADC_SHELLCONFIG_ADC_EMUL_SHELL (requires :kconfig:option:CONFIG_ADC_EMUL)Use the following macros for adding shell commands:
SHELL_CMD_REGISTER - Create root command. All root commands must
have different name.SHELL_COND_CMD_REGISTER - Conditionally (if compile time flag is
set) create root command. All root commands must have different name.SHELL_CMD_ARG_REGISTER - Create root command with arguments.
All root commands must have different name.SHELL_COND_CMD_ARG_REGISTER - Conditionally (if compile time flag
is set) create root command with arguments. All root commands must have
different name.SHELL_CMD - Initialize a command.SHELL_COND_CMD - Initialize a command if compile time flag is set.SHELL_EXPR_CMD - Initialize a command if compile time expression is
non-zero.SHELL_CMD_ARG - Initialize a command with arguments.SHELL_COND_CMD_ARG - Initialize a command with arguments if compile
time flag is set.SHELL_EXPR_CMD_ARG - Initialize a command with arguments if compile
time expression is non-zero.SHELL_STATIC_SUBCMD_SET_CREATE - Create a static subcommands
array.SHELL_SUBCMD_DICT_SET_CREATE - Create a dictionary subcommands
array.SHELL_DYNAMIC_CMD_CREATE - Create a dynamic subcommands array.Commands can be created in any file in the system that includes
:zephyr_file:include/zephyr/shell/shell.h. All created commands are available for all
shell instances.
Example code demonstrating how to create a root command with static subcommands.
.. image:: images/static_cmd.PNG :align: center :alt: Command tree with static commands.
.. code-block:: c
/* Creating subcommands (level 1 command) array for command "demo". */
SHELL_STATIC_SUBCMD_SET_CREATE(sub_demo,
SHELL_CMD(params, NULL, "Print params command.",
cmd_demo_params),
SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping),
SHELL_SUBCMD_SET_END
);
/* Creating root (level 0) command "demo" */
SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL);
Example implementation can be found under following location:
:zephyr_file:samples/subsys/shell/shell_module/src/main.c.
This is a special kind of static commands. Dictionary commands can be used every time you want to use a pair: (string <-> corresponding data) in a command handler. The string is usually a verbal description of a given data. The idea is to use the string as a command syntax that can be prompted by the shell and corresponding data can be used to process the command.
Let's use an example. Suppose you created a command to set an ADC gain. It is a perfect place where a dictionary can be used. The dictionary would be a set of pairs: (string: gain_value, int: value) where int value could be used with the ADC driver API.
Abstract code for this task would look like this:
.. code-block:: c
static int gain_cmd_handler(const struct shell *sh,
size_t argc, char **argv, void *data)
{
int gain;
/* data is a value corresponding to called command syntax */
gain = (int)data;
adc_set_gain(gain);
shell_print(sh, "ADC gain set to: %s\n"
"Value send to ADC driver: %d",
argv[0],
gain);
return 0;
}
SHELL_SUBCMD_DICT_SET_CREATE(sub_gain, gain_cmd_handler,
(gain_1, 1, "gain 1"), (gain_2, 2, "gain 2"),
(gain_1_2, 3, "gain 1/2"), (gain_1_4, 4, "gain 1/4")
);
SHELL_CMD_REGISTER(gain, &sub_gain, "Set ADC gain", NULL);
This is how it would look like in the shell:
.. image:: images/dict_cmd.png :align: center :alt: Dictionary commands example.
Example code demonstrating how to create a root command with static and dynamic subcommands. At the beginning dynamic command list is empty. New commands can be added by typing:
.. code-block:: none
dynamic add <new_dynamic_command>
Newly added commands can be prompted or autocompleted with the :kbd:Tab key.
.. image:: images/dynamic_cmd.PNG :align: center :alt: Command tree with static and dynamic commands.
.. code-block:: c
/* Buffer for 10 dynamic commands */
static char dynamic_cmd_buffer[10][50];
/* commands counter */
static uint8_t dynamic_cmd_cnt;
/* Function returning command dynamically created
* in dynamic_cmd_buffer.
*/
static void dynamic_cmd_get(size_t idx,
struct shell_static_entry *entry)
{
if (idx < dynamic_cmd_cnt) {
entry->syntax = dynamic_cmd_buffer[idx];
entry->handler = NULL;
entry->subcmd = NULL;
entry->help = "Show dynamic command name.";
} else {
/* if there are no more dynamic commands available
* syntax must be set to NULL.
*/
entry->syntax = NULL;
}
}
SHELL_DYNAMIC_CMD_CREATE(m_sub_dynamic_set, dynamic_cmd_get);
SHELL_STATIC_SUBCMD_SET_CREATE(m_sub_dynamic,
SHELL_CMD(add, NULL,"Add new command to dynamic_cmd_buffer and"
" sort them alphabetically.",
cmd_dynamic_add),
SHELL_CMD(execute, &m_sub_dynamic_set,
"Execute a command.", cmd_dynamic_execute),
SHELL_CMD(remove, &m_sub_dynamic_set,
"Remove a command from dynamic_cmd_buffer.",
cmd_dynamic_remove),
SHELL_CMD(show, NULL,
"Show all commands in dynamic_cmd_buffer.",
cmd_dynamic_show),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_REGISTER(dynamic, &m_sub_dynamic,
"Demonstrate dynamic command usage.", cmd_dynamic);
Example implementation can be found under following location:
:zephyr_file:samples/subsys/shell/shell_module/src/dynamic_cmd.c.
Each command or subcommand may have a handler. The shell executes the handler that is found deepest in the command tree and further subcommands (without a handler) are passed as arguments. Characters within parentheses are treated as one argument. If shell won't find a handler it will display an error message.
Commands can be also executed from a user application using any active backend
and a function :c:func:shell_execute_cmd, as shown in this example:
.. code-block:: c
int main(void)
{
/* Below code will execute "clear" command on a DUMMY backend */
shell_execute_cmd(NULL, "clear");
/* Below code will execute "shell colors off" command on
* an UART backend
*/
shell_execute_cmd(shell_backend_uart_get_ptr(),
"shell colors off");
}
Enable the DUMMY backend by setting the Kconfig
:kconfig:option:CONFIG_SHELL_BACKEND_DUMMY option.
Let's assume a command structure as in the following figure, where:
root_cmd - root command without a handlercmd_xxx_h - command has a handlercmd_xxx - command does not have a handler.. image:: images/execution.png :align: center :alt: Command tree with static commands.
Example 1
^^^^^^^^^
Sequence: :c:macro:root_cmd :c:macro:cmd_1_h :c:macro:cmd_12_h
:c:macro:cmd_121_h :c:macro:parameter will execute command
:c:macro:cmd_121_h and :c:macro:parameter will be passed as an argument.
Example 2
^^^^^^^^^
Sequence: :c:macro:root_cmd :c:macro:cmd_2 :c:macro:cmd_22_h
:c:macro:parameter1 :c:macro:parameter2 will execute command
:c:macro:cmd_22_h and :c:macro:parameter1 :c:macro:parameter2
will be passed as an arguments.
Example 3
^^^^^^^^^
Sequence: :c:macro:root_cmd :c:macro:cmd_1_h :c:macro:parameter1
:c:macro:cmd_121_h :c:macro:parameter2 will execute command
:c:macro:cmd_1_h and :c:macro:parameter1, :c:macro:cmd_121_h and
:c:macro:parameter2 will be passed as an arguments.
Example 4
^^^^^^^^^
Sequence: :c:macro:root_cmd :c:macro:parameter :c:macro:cmd_121_h
:c:macro:parameter2 will not execute any command.
Simple command handler implementation:
.. code-block:: c
static int cmd_handler(const struct shell *sh, size_t argc,
char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
shell_fprintf(shell, SHELL_INFO, "Print info message\n");
shell_print(sh, "Print simple text.");
shell_warn(sh, "Print warning text.");
shell_error(sh, "Print error text.");
return 0;
}
Function :c:func:shell_fprintf or the shell print macros:
:c:macro:shell_print, :c:macro:shell_info, :c:macro:shell_warn and
:c:macro:shell_error can be used from the command handler or from threads,
but not from an interrupt context. Instead, interrupt handlers should use
:ref:logging_api for printing.
Every user-defined command or subcommand can have its own help description.
The help for commands and subcommands can be created with respective macros:
:c:macro:SHELL_CMD_REGISTER, :c:macro:SHELL_CMD_ARG_REGISTER,
:c:macro:SHELL_CMD, and :c:macro:SHELL_CMD_ARG.
Shell prints this help message when you call a command
or subcommand with -h or --help parameter.
In the subcommand handler, you can access both the parameters passed to
commands or the parent commands, depending on how you index argv.
argv with positive numbers, you can access the parameters.argv with negative numbers, you can access the parent
commands.argv index of 0... code-block:: c
static int cmd_handler(const struct shell *sh, size_t argc,
char **argv)
{
ARG_UNUSED(argc);
/* If it is a subcommand handler parent command syntax
* can be found using argv[-1].
*/
shell_print(sh, "This command has a parent command: %s",
argv[-1]);
/* Print this command syntax */
shell_print(sh, "This command syntax is: %s", argv[0]);
/* Print first argument */
shell_print(sh, "%s", argv[1]);
return 0;
}
These commands are activated by :kconfig:option:CONFIG_SHELL_CMDS set to y.
:command:clear - Clears the screen.
:command:history - Shows the recently entered commands.
:command:resize - Must be executed when terminal width is different than 80
characters or after each change of terminal width. It ensures proper
multiline text display and :kbd:←, :kbd:→, :kbd:End, :kbd:Home keys
handling. Currently this command works only with UART flow control switched
on. It can be also called with a subcommand:
default - Shell will send terminal width = 80 to the
terminal and assume successful delivery.These command needs extra activation:
:kconfig:option:CONFIG_SHELL_CMDS_RESIZE set to y.
:command:select - It can be used to set new root command. Exit to main
command tree is with alt+r. This command needs extra activation:
:kconfig:option:CONFIG_SHELL_CMDS_SELECT set to y.
:command:shell - Root command with useful shell-related subcommands like:
echo - Toggles shell echo.
colors - Toggles colored syntax. This might be helpful in
case of Bluetooth shell to limit the amount of transferred bytes.stats - Shows shell statistics... _tab-feature:
Tab Feature
The Tab button can be used to suggest commands or subcommands. This feature
is enabled by :kconfig:option:CONFIG_SHELL_TAB set to y.
It can also be used for partial or complete auto-completion of commands.
This feature is activated by
:kconfig:option:CONFIG_SHELL_TAB_AUTOCOMPLETION set to y.
When user starts writing a command and presses the :kbd:Tab button then
the shell will do one of 3 possible things:
.. image:: images/tab_prompt.png :align: center :alt: Tab Feature usage example
.. _history-feature:
History Feature
This feature enables commands history in the shell. It is activated by:
:kconfig:option:CONFIG_SHELL_HISTORY set to y. History can be accessed
using keys: :kbd:↑ :kbd:↓ or :kbd:Ctrl+n and :kbd:Ctrl+p
if meta keys are active.
Number of commands that can be stored depends on size
of :kconfig:option:CONFIG_SHELL_HISTORY_BUFFER parameter.
Wildcards Feature
The shell module can handle wildcards. Wildcards are interpreted correctly
when expanded command and its subcommands do not have a handler. For example,
if you want to set logging level to err for the app and app_test
modules you can execute the following command:
.. code-block:: none
log enable err a*
.. image:: images/wildcard.png :align: center :alt: Wildcard usage example
This feature is activated by :kconfig:option:CONFIG_SHELL_WILDCARD set to y.
.. note::
When the wildcard feature is enabled, the characters * and ?
cannot be used as normal characters in commands or arguments.
Meta Keys Feature
The shell module supports the following meta keys:
.. list-table:: Implemented meta keys :widths: 10 40 :header-rows: 1
Ctrl+aCtrl+bCtrl+cCtrl+dCtrl+eCtrl+fCtrl+kCtrl+lCtrl+nCtrl+pCtrl+tCONFIG_SHELL_LOG_BACKEND is set.Ctrl+uCtrl+wAlt+bAlt+fThis feature is activated by :kconfig:option:CONFIG_SHELL_METAKEYS set to y.
sys_getopt Feature
Some shell users apart from subcommands might need to use options as well.
the arguments string, looking for supported options. Typically, this task
is accomplished by the getopt family functions.
For this purpose shell supports a variant of the getopt and getopt_long libraries from
the FreeBSD project called sys_getopt and sys_getopt_long. This feature is activated by:
:kconfig:option:CONFIG_GETOPT set to y and :kconfig:option:CONFIG_GETOPT_LONG
set to y.
This feature can be used in thread safe as well as non thread safe manner. The former is full compatible with regular getopt usage while the latter a bit differs.
An example non-thread safe usage:
.. code-block:: c
char *cvalue = NULL; while ((char c = sys_getopt(argc, argv, "abhc:")) != -1) { switch (c) { case 'c': cvalue = sys_getopt_optarg; break; default: break; } }
An example thread safe usage:
.. code-block:: c
char *cvalue = NULL; struct sys_getopt_state *state; while ((char c = sys_getopt(argc, argv, "abhc:")) != -1) { state = sys_getopt_state_get(); switch (c) { case 'c': cvalue = state->optarg; break; default: break; } }
Thread safe sys_getopt functionality is activated by
:kconfig:option:CONFIG_SHELL_GETOPT set to y.
Obscured Input Feature
With the obscured input feature, the shell can be used for implementing a login prompt or other user interaction whereby the characters the user types should not be revealed on screen, such as when entering a password.
Once the obscured input has been accepted, it is normally desired to return the
shell to normal operation. Such runtime control is possible with the
shell_obscure_set function.
An example of login and logout commands using this feature is located in
:zephyr_file:samples/subsys/shell/shell_module/src/main.c and the config file
:zephyr_file:samples/subsys/shell/shell_module/prj_login.conf.
This feature is activated upon startup by :kconfig:option:CONFIG_SHELL_START_OBSCURED
set to y. With this set either way, the option can still be controlled later
at runtime. :kconfig:option:CONFIG_SHELL_CMDS_SELECT is useful to prevent entry
of any other command besides a login command, by means of the
shell_set_root_cmd function. Likewise, :kconfig:option:CONFIG_SHELL_PROMPT_UART
allows you to set the prompt upon startup, but it can be changed later with the
shell_prompt_change function.
.. _shell-readline:
Reading User Input
The shell provides a :c:func:shell_readline function that allows command handlers
to interactively read a line of input from the user. This is useful for implementing
commands that need to prompt the user for additional information, such as confirmation
dialogs, multi-step wizards, or interactive data entry.
The function reads from the shell transport until a newline character is received, storing the data in a provided buffer. The newline character itself is not included in the buffer. The buffer is automatically null-terminated on success.
.. note::
The :c:func:shell_readline function should be called from the shell thread in a
shell command handler and blocks the thread until a result is returned.
Example usage:
.. code-block:: c
static int cmd_read_secret(const struct shell *sh, size_t argc, char **argv) { uint8_t input_buf[256]; int ret;
shell_fprintf_normal(sh, "Enter your secret: ");
shell_obscure_set(sh, true);
ret = shell_readline(sh, input_buf, sizeof(input_buf), K_SECONDS(10));
shell_obscure_set(sh, false);
if (ret < 0) {
if (ret == -ETIMEDOUT) {
shell_error(sh, "Timeout waiting for input");
} else if (ret == -ECANCELED) {
shell_error(sh, "Input canceled");
} else if (ret == -ENOBUFS) {
shell_error(sh, "Input too long");
}
return ret;
}
shell_print(sh, "Secret input received (%d bytes)", ret);
return 0;
}
Shell Logger Backend Feature
Shell instance can act as the :ref:logging_api backend. Shell ensures that log
messages are correctly multiplexed with shell output. Log messages from logger
thread are enqueued and processed in the shell thread. Logger thread will block
for configurable amount of time if queue is full, blocking logger thread context
for that time. Oldest log message is removed from the queue after timeout and
new message is enqueued. Use the shell stats show command to retrieve
number of log messages dropped by the shell instance. Log queue size and timeout
are :c:macro:SHELL_DEFINE arguments.
This feature is activated by: :kconfig:option:CONFIG_SHELL_LOG_BACKEND set to y.
.. warning:: Enqueuing timeout must be set carefully when multiple backends are used in the system. The shell instance could have a slow transport or could block, for example, by a UART with hardware flow control. If timeout is set too high, the logger thread could be blocked and impact other logger backends.
.. warning::
As the shell is a complex logger backend, it can not output logs if
the application crashes before the shell thread is running. In this
situation, you can enable one of the simple logging backends instead,
such as UART (:kconfig:option:CONFIG_LOG_BACKEND_UART) or
RTT (:kconfig:option:CONFIG_LOG_BACKEND_RTT), which are available earlier
during system initialization.
RTT Backend Channel Selection
Instead of using the shell as a logger backend, RTT shell backend and RTT log
backend can also be used simultaneously, but over different channels. By
separating them, the log can be captured or monitored without shell output or
the shell may be scripted without log interference. Enabling both the Shell RTT
backend and the Log RTT backend does not work by default, because both default
to channel 0. There are two options:
The Shell buffer can use an alternate channel, for example using
:kconfig:option:CONFIG_SHELL_BACKEND_RTT_BUFFER set to 1.
This allows monitoring the log using JLinkRTTViewer <https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/#j-link-rtt-viewer>_
while a script interfaces over channel 1.
The Log buffer can use an alternate channel, for example using
:kconfig:option:CONFIG_LOG_BACKEND_RTT_BUFFER set to 1.
This allows interactive use of the shell through JLinkRTTViewer, while the log
is written to file.
See shell backends <backends_>_ for details on how to enable RTT as a Shell backend.
Usage
The following code shows a simple use case of this library:
.. code-block:: c
int main(void)
{
}
static int cmd_demo_ping(const struct shell *sh, size_t argc,
char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
shell_print(sh, "pong");
return 0;
}
static int cmd_demo_params(const struct shell *sh, size_t argc,
char **argv)
{
int cnt;
shell_print(sh, "argc = %d", argc);
for (cnt = 0; cnt < argc; cnt++) {
shell_print(sh, " argv[%d] = %s", cnt, argv[cnt]);
}
return 0;
}
/* Creating subcommands (level 1 command) array for command "demo". */
SHELL_STATIC_SUBCMD_SET_CREATE(sub_demo,
SHELL_CMD(params, NULL, "Print params command.",
cmd_demo_params),
SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping),
SHELL_SUBCMD_SET_END
);
/* Creating root (level 0) command "demo" without a handler */
SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL);
/* Creating root (level 0) command "version" */
SHELL_CMD_REGISTER(version, NULL, "Show kernel version", cmd_version);
Users may use the :kbd:Tab key to complete a command/subcommand or to see the
available subcommands for the currently entered command level.
For example, when the cursor is positioned at the beginning of the command
line and the :kbd:Tab key is pressed, the user will see all root (level 0)
commands:
.. code-block:: none
clear demo shell history log resize version
.. note::
To view the subcommands that are available for a specific command, you
must first type a :kbd:space after this command and then hit
:kbd:Tab.
These commands are registered by various modules, for example:
clear, :command:shell, :command:history, and :command:resize
are built-in commands which have been registered by
:zephyr_file:subsys/shell/shell.cdemo and :command:version have been registered in example code
above by main.clog has been registered by :zephyr_file:subsys/logging/log_cmds.cThen, if a user types a :command:demo command and presses the :kbd:Tab key,
the shell will only print the subcommands registered for this command:
.. code-block:: none
params ping
API Reference
.. doxygengroup:: shell_api