mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-01 19:53:17 +00:00
Shell handler can now return an int value. This change has been reflected in shell.rst. Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
520 lines
16 KiB
ReStructuredText
520 lines
16 KiB
ReStructuredText
.. _shell:
|
|
|
|
Shell
|
|
######
|
|
|
|
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:
|
|
|
|
* Support for multiple instances.
|
|
* Advanced cooperation with the :ref:`logger`.
|
|
* Support for static and dynamic commands.
|
|
* Smart command completion with the :kbd:`Tab` key.
|
|
* Built-in commands: :command:`clear`, :command:`shell`, :command:`colors`,
|
|
:command:`echo`, :command:`history` and :command:`resize`.
|
|
* Viewing recently executed commands using keys: :kbd:`↑` :kbd:`↓`.
|
|
* Text edition using keys: :kbd:`←`, :kbd:`→`, :kbd:`Backspace`,
|
|
:kbd:`Delete`, :kbd:`End`, :kbd:`Home`, :kbd:`Insert`.
|
|
* Support for ANSI escape codes: ``VT100`` and ``ESC[n~`` for cursor control
|
|
and color printing.
|
|
* Support for multiline commands.
|
|
* Built-in handler to display help for the commands.
|
|
* Support for wildcards: ``*`` and ``?``.
|
|
* Support for meta keys.
|
|
* Kconfig configuration to optimize memory usage.
|
|
|
|
The module can be connected to any transport for command input and output.
|
|
At this point, the following transport layers are implemented:
|
|
|
|
* UART
|
|
|
|
See the :ref:`shell_api` documentation for more information.
|
|
|
|
Commands
|
|
********
|
|
|
|
Shell commands are organized in a tree structure and grouped into the following
|
|
types:
|
|
|
|
* Root command (level 0): Gathered and alphabetically sorted in a dedicated
|
|
memory section.
|
|
* Static subcommand (level > 0): Number and syntax must be known during compile
|
|
time. Created in the software module.
|
|
* Dynamic subcommand (level > 0): Number and syntax does not need to be known
|
|
during compile time. Created in the software module.
|
|
|
|
Creating commands
|
|
=================
|
|
|
|
Use the following macros for adding shell commands:
|
|
|
|
* :c:macro:`SHELL_CMD_REGISTER` - Create root command. All root commands must
|
|
have different name.
|
|
* :c:macro:`SHELL_CMD` - Initialize a command.
|
|
* :c:macro:`SHELL_CREATE_STATIC_SUBCMD_SET` - Create a static subcommands
|
|
array. Static subcommands must be added in alphabetical order to ensure
|
|
correct smart completion.
|
|
* :c:macro:`SHELL_SUBCMD_SET_END` - shall be placed as last in
|
|
:c:macro:`SHELL_CREATE_STATIC_SUBCMD_SET` macro.
|
|
* :c:macro:`SHELL_CREATE_DYNAMIC_CMD` - Create a dynamic subcommands array.
|
|
Dynamic subcommands must be returned in alphabetical order to ensure correct
|
|
smart completion.
|
|
|
|
Commands can be created in any file in the system that includes
|
|
:file:`include/shell/shell.h`. All created commands are available for all
|
|
shell instances.
|
|
|
|
Static commands
|
|
---------------
|
|
|
|
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".
|
|
* Subcommands must be added in alphabetical order to ensure correct
|
|
* command autocompletion.
|
|
*/
|
|
SHELL_CREATE_STATIC_SUBCMD_SET(sub_demo)
|
|
{
|
|
/* Alphabetically sorted. */
|
|
SHELL_CMD(params, NULL, "Print params command.",
|
|
cmd_demo_params),
|
|
SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping),
|
|
SHELL_SUBCMD_SET_END /* Array terminated. */
|
|
};
|
|
/* Creating root (level 0) command "demo" */
|
|
SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL);
|
|
|
|
Example implementation can be found under following location:
|
|
:file:`samples/subsys/shell/shell_module/src/main.c`.
|
|
|
|
Dynamic commands
|
|
----------------
|
|
|
|
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 u8_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) {
|
|
/* m_dynamic_cmd_buffer must be sorted alphabetically
|
|
* to ensure correct Shell autocompletion
|
|
*/
|
|
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_CREATE_DYNAMIC_CMD(m_sub_dynamic_set, dynamic_cmd_get);
|
|
SHELL_CREATE_STATIC_SUBCMD_SET(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:
|
|
:file:`samples/subsys/shell/shell_module/src/dynamic_cmd.c`.
|
|
|
|
Commands execution
|
|
==================
|
|
|
|
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 wont find a handler it will display an error message.
|
|
|
|
Command handler
|
|
----------------
|
|
|
|
Simple command handler implementation:
|
|
|
|
.. code-block:: c
|
|
|
|
static int cmd_handler(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
"Print simple text.\r\n");
|
|
|
|
shell_fprintf(shell, SHELL_WARNING,
|
|
"Print warning text.\r\n");
|
|
|
|
shell_fprintf(shell, SHELL_ERROR,
|
|
"Print error text.\r\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
.. warning::
|
|
Do not use function :cpp:func:`shell_fprintf` outside of the command
|
|
handler because this might lead to incorrect text display on the
|
|
screen. If any text should be displayed outside of the command context,
|
|
then use the :ref:`logger`.
|
|
|
|
Command help
|
|
------------
|
|
|
|
Every user-defined command, subcommand, or option can have its own help
|
|
description. The help for commands and subcommands can be created with
|
|
respective macros: :c:macro:`SHELL_CMD_REGISTER` and :c:macro:`SHELL_CMD`.
|
|
In addition, you can define options for commands or subcommands using the
|
|
macro :c:macro:`SHELL_OPT`. By default, each and every command or subcommand
|
|
has these two options implemented: ``-h`` and ``--help``.
|
|
|
|
In order to add help functionality to a command or subcommand, you must
|
|
implement the help handler by either calling :cpp:func:`shell_cmd_precheck`
|
|
or pair of functions :cpp:func:`shell_help_requested` and
|
|
:cpp:func:`shell_help_print`. The former is more convenient as it also
|
|
checks for valid arguments count.
|
|
|
|
.. code-block:: c
|
|
|
|
static int cmd_dummy_1(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
ARG_UNUSED(argv);
|
|
|
|
/* Function shell_cmd_precheck will do one of below actions:
|
|
* 1. print help if command called with -h or --help
|
|
* 2. print error message if argc > 2
|
|
*
|
|
* Each of these actions can be deactivated in Kconfig.
|
|
*/
|
|
if (!shell_cmd_precheck(shell, (argc <= 2), NULL, 0) {
|
|
return 0;
|
|
}
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
"Command called with no -h or --help option."
|
|
"\r\n");
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_dummy_2(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
if (hell_help_requested(shell) {
|
|
shell_help_print(shell, NULL, 0);
|
|
} else {
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
"Command called with no -h or --help option."
|
|
"\r\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Command options
|
|
---------------
|
|
|
|
When possible, use subcommands instead of options. Options apply mainly in the
|
|
case when an argument with ``-`` or ``--`` is requested. The main benefit of
|
|
using subcommands is that they can be prompted or completed with the :kbd:`Tab`
|
|
key. In addition, subcommands can have their own handler, which limits the
|
|
usage of ``if - else if`` statements combination with the ``strcmp`` function
|
|
in command handler.
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
static int cmd_with_options(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
/* Dummy options showing options usage */
|
|
static const struct shell_getopt_option opt[] = {
|
|
SHELL_OPT(
|
|
"--test",
|
|
"-t",
|
|
"test option help string"
|
|
),
|
|
SHELL_OPT(
|
|
"--dummy",
|
|
"-d",
|
|
"dummy option help string"
|
|
)
|
|
};
|
|
|
|
/* If command will be called with -h or --help option
|
|
* all declared options will be listed in the help message
|
|
*/
|
|
if (!shell_cmd_precheck(shell, (argc <= 2), opt,
|
|
sizeof(opt)/sizeof(opt[1]))) {
|
|
return 0;
|
|
}
|
|
|
|
/* checking if command was called with test option */
|
|
if (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--test")) {
|
|
shell_fprintf(shell, SHELL_NORMAL, "Command called with -t"
|
|
" or --test option.\r\n");
|
|
return 0;
|
|
}
|
|
|
|
/* checking if command was called with dummy option */
|
|
if (!strcmp(argv[1], "-d") || !strcmp(argv[1], "--dummy")) {
|
|
shell_fprintf(shell, SHELL_NORMAL, "Command called with -d"
|
|
" or --dummy option.\r\n");
|
|
return 0;
|
|
}
|
|
|
|
shell_fprintf(shell, SHELL_WARNING,
|
|
"Command called with no valid option.\r\n");
|
|
return 0;
|
|
}
|
|
|
|
Parent commands
|
|
---------------
|
|
|
|
In the subcommand handler, you can access both the parameters passed to
|
|
commands or the parent commands, depending on how you index ``argv``.
|
|
|
|
* When indexing ``argv`` with positive numbers, you can access the parameters.
|
|
* When indexing ``argv`` with negative numbers, you can access the parent
|
|
commands.
|
|
* The subcommand to which the handler belongs has the ``argv`` value of 0.
|
|
|
|
.. code-block:: c
|
|
|
|
static int cmd_handler(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
ARG_UNUSED(argc);
|
|
|
|
/* If it is a subcommand handler parent command syntax
|
|
* can be found using argv[-1].
|
|
*/
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
"This command has a parent command: %s\r\n",
|
|
argv[-1]);
|
|
|
|
/* Print this command syntax */
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
"This command syntax is: %s\r\n",
|
|
argv[0]);
|
|
|
|
/* Print first argument */
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
"This command has an argument: %s\r\n",
|
|
argv[1]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Built-in commands
|
|
=================
|
|
|
|
* :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:
|
|
|
|
* :command:`default` - Shell will send terminal width = 80 to the
|
|
terminal and assume successful delivery.
|
|
|
|
* :command:`shell` - Root command with useful shell-related subcommands like:
|
|
|
|
* :command:`echo` - Toggles shell echo.
|
|
* :command:`colors` - Toggles colored syntax. This might be helpful in
|
|
case of Bluetooth shell to limit the amount of transferred bytes.
|
|
* :command:`stats` - Shows shell statistics.
|
|
|
|
Wildcards
|
|
*********
|
|
|
|
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
|
|
|
|
Meta keys
|
|
*********
|
|
|
|
The shell module supports the following meta keys:
|
|
|
|
.. list-table:: Implemented meta keys
|
|
:widths: 10 40
|
|
:header-rows: 1
|
|
|
|
* - Meta keys
|
|
- Action
|
|
* - ctrl + a
|
|
- Moves the cursor to the beginning of the line.
|
|
* - ctrl + c
|
|
- Preserves the last command on the screen and starts a new command in
|
|
a new line.
|
|
* - ctrl + e
|
|
- Moves the cursor to the end of the line.
|
|
* - ctrl + l
|
|
- Clears the screen and leaves the currently typed command at the top of
|
|
the screen.
|
|
* - ctrl + u
|
|
- Clears the currently typed command.
|
|
* - ctrl + w
|
|
- Removes the word or part of the word to the left of the cursor. Words
|
|
separated by period instead of space are treated as one word.
|
|
|
|
Usage
|
|
*****
|
|
|
|
Use the :c:macro:`SHELL_DEFINE` macro to create an instance of the shell.
|
|
Pass the expected newline character to this macro: either ``\r`` or ``\n``,
|
|
otherwise the shell will not respond correctly to the :kbd:`Enter` key.
|
|
|
|
The following code shows a simple use case of this library:
|
|
|
|
.. code-block:: c
|
|
|
|
/* Defining shell backend */
|
|
SHELL_UART_DEFINE(shell_transport_uart);
|
|
|
|
/* Creating shell instance */
|
|
SHELL_DEFINE(uart_shell, "uart:~$ ", &shell_transport_uart, '\r', 10);
|
|
|
|
void main(void)
|
|
{
|
|
(void)shell_init(&uart_shell, NULL, true, true, LOG_LEVEL_INF);
|
|
}
|
|
|
|
static int cmd_demo_ping(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, "pong\r\n");
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_demo_params(const struct shell *shell, size_t argc,
|
|
char **argv)
|
|
{
|
|
int cnt;
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, "argc = %d\r\n", argc);
|
|
for (cnt = 0; cnt < argc; cnt++) {
|
|
shell_fprintf(shell, SHELL_NORMAL,
|
|
" argv[%d] = %s\r\n", cnt, argv[cnt]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Creating subcommands (level 1 command) array for command "demo".
|
|
* Subcommands must be added in alphabetical order
|
|
*/
|
|
SHELL_CREATE_STATIC_SUBCMD_SET(sub_demo)
|
|
{
|
|
/* Alphabetically sorted. */
|
|
SHELL_CMD(params, NULL, "Print params command.",
|
|
cmd_demo_params),
|
|
SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping),
|
|
SHELL_SUBCMD_SET_END /* Array terminated. */
|
|
};
|
|
/* 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:
|
|
|
|
* :command:`clear`, :command:`shell`, :command:`history`, and :command:`resize`
|
|
are built-in commands which have been registered by
|
|
:file:`subsys/shell/shell.c`
|
|
* :command:`demo` and :command:`version` have been registered in example code
|
|
above by main.c
|
|
* :command:`log` has been registered by :file:`subsys/logging/log_cmds.c`
|
|
|
|
Then, 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
|
|
|
|
|