百科.dev
全部条目在线工具AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
L

letter-shell

> 编程语言
开源

信封

1.9K stars0 点赞1 次浏览
访问官网GitHub

工具介绍

信封

letter shell 3.x

一个功能强大的嵌入式shell

  • letter shell 3.x
    • 简介
    • 功能
    • 移植说明
    • 使用方式
      • 函数定义
        • main函数形式
        • 普通C函数形式
      • 变量使用
      • 在函数中获取当前shell对象
      • 执行未导出函数
    • 命令定义
      • 定义方式
      • 定义宏说明
      • 命令属性字段说明
    • 代理函数和代理参数解析
    • 函数签名
      • 自定义类型解析
      • 数组参数
    • 权限系统说明
    • 锁说明
    • 伴生对象
    • 尾行模式
    • 建议终端软件
    • 命令遍历工具
    • x86 demo

简介

letter shell是一个C语言编写的,可以嵌入在程序中的嵌入式shell,主要面向嵌入式设备,以C语言函数为运行单位,可以通过命令行调用,运行程序中的函数

相对2.x版本,letter shell 3.x增加了用户管理,权限管理,以及对文件系统的初步支持

此外3.x版本修改了命令格式和定义,2.x版本的工程需要经过简单的修改才能完成迁移

若只需要使用基础功能,可以使用letter shell 2.x版本

使用说明可参考Letter shell 3.0 全新出发

如果从3.0版本迁移到3.1以上版本,请注意3.1版本对读写函数原型的修改

功能

  • 命令自动补全
  • 快捷键功能定义
  • 命令权限管理
  • 用户管理
  • 变量支持
  • 代理函数和参数代理解析

移植说明

  1. 定义shell对象

    c
    Shell shell;
  2. 定义shell读,写函数

    对于使用letter shell 3.0版本,读写函数原型如下:

    c
    /**
     * @brief shell读取数据函数原型
     *
     * @param char shell读取的字符
     *
     * @return char 0 读取数据成功
     * @return char -1 读取数据失败
     */
    typedef signed char (*shellRead)(char *);
    
    /**
     * @brief shell写数据函数原型
     *
     * @param const char 需写的字符
     */
    typedef void (*shellWrite)(const char);

    对于使用letter shell 3.1版本,为了优化效率,修改了读写函数原型,如下:

    c
    /**
     * @brief shell读取数据函数原型
     *
     * @param data shell读取的字符
     * @param len 请求读取的字符数量
     *
     * @return unsigned short 实际读取到的字符数量
     */
    typedef unsigned short (*shellRead)(char *data, unsigned short len);
    
    /**
     * @brief shell写数据函数原型
     *
     * @param data 需写的字符数据
     * @param len 需要写入的字符数
     *
     * @return unsigned short 实际写入的字符数量
     */
    typedef unsigned short (*shellWrite)(char *data, unsigned short len);
  3. 申请一片缓冲区

    c
    char shellBuffer[512];
  4. 调用shellInit进行初始化

    c
    shell.read = shellRead;
    shell.write = shellWrite;
    shellInit(&shell, shellBuffer, 512);
  5. 调用(建立)shell任务

    对于运行在操作系统的情况,建立shellTask任务(确保sell_cfg.h中的配置无误),任务参数为shell对象

    c
    OsTaskCreate(shellTask, &shell, ...);

    对于裸机环境,在主循环中调用shellTask,或者在接收到数据时,调用shellHandler

  6. 说明

    • 对于中断方式使用shell,不用定义shell->read,但需要在中断中调用shellHandler
    • 对于使用操作系统的情况,使能SHEHLL_TASK_WHILE宏,然后创建shellTask任务
  7. 其他配置

    • 定义宏SHELL_GET_TICK()为获取系统tick函数,使能tab双击操作,用户长帮助补全
  8. 配置宏

    shell_cfg.h文件中包含了所有用于配置shell的宏,在使用前,需要根据需要进行配置

    建议采用 overlay 的方式,新建一个头文件,例如 shell_cfg_user.h,然后定义编译宏 SHELL_CFG_USER="shell_cfg_user.h",在这个头文件中添加需要修改的配置即可

    宏 意义
    SHELL_TASK_WHILE 是否使用默认shell任务while循环
    SHELL_USING_CMD_EXPORT 是否使用命令导出方式
    SHELL_USING_COMPANION 是否使用shell伴生对象功能
    SHELL_SUPPORT_END_LINE 是否支持shell尾行模式
    SHELL_HELP_LIST_USER 是否在输入命令列表中列出用户
    SHELL_HELP_LIST_VAR 是否在输入命令列表中列出变量
    SHELL_HELP_LIST_KEY 是否在输入命令列表中列出按键
    SHELL_ENTER_LF 使用LF作为命令行回车触发
    SHELL_ENTER_CR 使用CR作为命令行回车触发
    SHELL_ENTER_CRLF 使用CRLF作为命令行回车触发
    SHELL_EXEC_UNDEF_FUNC 使用执行未导出函数的功能
    SHELL_COMMAND_MAX_LENGTH shell命令最大长度
    SHELL_PARAMETER_MAX_NUMBER shell命令参数最大数量
    SHELL_HISTORY_MAX_NUMBER 历史命令记录数量
    SHELL_DOUBLE_CLICK_TIME 双击间隔(ms)
    SHELL_QUICK_HELP 快速帮助
    SHELL_MAX_NUMBER 管理的最大shell数量
    SHELL_GET_TICK() 获取系统时间(ms)
    SHELL_USING_LOCK 是否使用锁
    SHELL_MALLOC(size) 内存分配函数(shell本身不需要)
    SHELL_FREE(obj) 内存释放函数(shell本身不需要)
    SHELL_SHOW_INFO 是否显示shell信息
    SHELL_CLS_WHEN_LOGIN 是否在登录后清除命令行
    SHELL_DEFAULT_USER shell默认用户
    SHELL_DEFAULT_USER_PASSWORD 默认用户密码
    SHELL_LOCK_TIMEOUT shell自动锁定超时
    SHELL_USING_FUNC_SIGNATURE 使用函数签名
    SHELL_SUPPORT_ARRAY_PARAM 支持数组参数

使用方式

函数定义

letter shell 3.x同时支持两种形式的函数定义方式,形如main函数定义的func(int argc, char *agrv[])以及形如普通C函数的定义func(int i, char *str, ...),两种函数定义方式适用于不同的场景

main函数形式

使用此方式,一个函数定义的例子如下:

c
int func(int argc, char *argv[])
{
    printf("%dparameter(s)\r\n", argc);
    for (char i = 1; i < argc; i++)
    {
        printf("%s\r\n", argv[i]);
    }
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), func, func, test);

终端调用

bash
letter:/$ func "hello world"
2 parameter(s)
hello world

普通C函数形式

使用此方式,shell会自动对参数进行转化处理,目前支持二进制,八进制,十进制,十六进制整形,字符,字符串的自动处理,如果需要其他类型的参数,请使用代理参数解析的方式(参考代理函数和代理参数解析),或者使用字符串的方式作为参数,自行进行处理,例子如下:

c
int func(int i, char ch, char *str)
{
    printf("input int: %d, char: %c, string: %s\r\n", i, ch, str);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), func, func, test);

终端调用

bash
letter:/$ func 666 'A' "hello world"
input int: 666, char: A, string: hello world

变量使用

letter shell 3.x支持导出变量,通过命令行查看,设置以及使用变量的值

  • 导出变量

    变量导出使用SHELL_EXPORT_VAR宏,支持整形(char, short, int),字符串,指针以及节点变量,变量导出需要使用引用的方式,如果不允许对变量进行修改,在属性中添加SHELL_CMD_READ_ONLY

    c
    int varInt = 0;
    SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_INT), varInt, &varInt, test);
    
    char str[] = "test string";
    SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_STRING), varStr, str, test);
    
    Log log;
    SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_POINT), log, &log, test);
  • 查看变量

    在命令行直接输入导出的变量名即可查看变量当前的值

    bash
    letter:/$ varInt
    varInt = 0, 0x00000000
    
    letter:/$ varStr
    varStr = "test string"
  • 修改变量

    使用setVar命令修改变量的值,对于字符串型变量,请确认字符串有分配足够的空间,指针类型的变量不可修改

    bash
    letter:/$ setVar varInt 45678
    varInt = 45678, 0x0000b26e
    
    letter:/$ setVar varStr "hello"
    varStr = "hello"
  • 使用变量

    letter shell 3.x的变量可以在命令中作为参数传递,对于需要传递结构体引用到命令中的场景特别适用,使用$+变量名的方式传递

    bash
    letter:/$ shellPrint $shell "hello world\r\n"
    hello world

在函数中获取当前shell对象

letter shell采取一个静态数组对定义的多个shell进行管理,shell数量可以修改宏SHELL_MAX_NUMBER定义(为了不使用动态内存分配,此处通过数据进行管理),从而,在shell执行的函数中,可以调用shellGetCurrent()获得当前活动的shell对象,从而可以实现某一个函数在不同的shell对象中发生不同的行为,也可以通过这种方式获得shell对象后,调用shellWriteString(shell, string)进行shell的输出

执行未导出函数

letter shell支持通过函数地址直接执行函数,可以方便执行那些没有导出,但是又临时需要使用的函数,使用命令exec [addr] [args]执行,使用此功能需要开启SHELL_EXEC_UNDEF_FUNC宏,注意,由于直接操作函数地址执行,如果给进的地址有误,可能引起程序崩溃

函数的地址可以通过编译生成的文件查找,比如说对于keil,可以在.map文件中查找到每个函数的地址,但是要注意有些平台可能需要要对地址做进一步处理,比如说对于 arm 平台,如果使用的是 Thumb 指令集,那么需要将地址的最低位置 1,比如说shellClear函数地址为0x08028620,则通过exec执行应为exec 0x08028621

其他编译器查找函数地址的方式和地址偏移的处理,请参考各编译器手册

命令定义

letter shell 3.x将可执行的函数命令定义,用户定义,按键定义以及变量定义统一归为命令定义,使用相同的结构储存,查找和执行

定义方式

letter shell 支持使用命令导出方式和命令表方式进行命令的添加,定义,通过宏SHELL_USING_CMD_EXPORT控制

命令导出方式支持keil,IAR以及GCC

  1. 命令导出方式

    letter shell 支持在函数体外部,采用定义常量的方式定义命令,例如SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE (SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,help, shellHelp, show command info\r\nhelp [cmd]);

    对于使用keil进行编译,需要在keil的target option中增加--keep shellCommand*,防止定义的命令被优化掉

    使用GCC编译时,需要在ld文件中的只读数据区(建议)添加:

    ld
    _shell_command_start = .;
    KEEP (*(shellCommand))
    _shell_command_end = .;
  2. 命令表方式

    • 当使用其他暂时不支持使用命令导出方式的编译器时,需要在shell_cmd_list.c文件的命令表中添加

      c
      const SHELL_CommandTypeDef shellDefaultCommandList[] =
      {
          SHELL_CMD_ITEM(
                     SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
                     help, shellHelp, show command info\r\nhelp [cmd]),
      };

定义宏说明

letter shell 3.x对可执行命令,按键,用户以及变量分别提供了一个宏,用于进行命令定义

  1. 可执行命令定义

    使用宏SHELL_EXPORT_CMD定义可执行命令,定义如下

…
  1. 变量定义

    使用宏SHELL_EXPORT_VAR定义变量,定义如下

…
变量定义时,`_value`应该是变量的引用,如果变量不允许修改,则需要在增加`SHELL_CMD_READ_ONLY`属性
  1. 用户定义

    使用宏SHELL_EXPORT_USER定义用户,定义如下

…
  1. 按键定义

    使用宏SHELL_EXPORT_KEY定义按键,定义如下

…
按键键值为在终端输入按键会发送的字符串序列,以大端模式表示,比如在SecureCRT中断,按下Tab键,会发送0x0B,则这个按键的键值为0x0B000000,如果按下方向上,会依次发送0x1B, 0x5B, 0x41, 则这个键的键值为0x1B5B4100

命令属性字段说明

在命令定义中,有一个attr字段,表示该命令的属性,具体定义为

c
union
{
    struct
    {
        unsigned char permission : 8;                       /**< command权限 */
        ShellCommandType type : 4;                          /**< command类型 */
        unsigned char enableUnchecked : 1;                  /**< 在未校验密码的情况下可用 */
        unsigned char  readOnly : 1;                        /**< 只读 */
        unsigned char reserve : 1;                          /**< 保留 */
        unsigned char paramNum : 4;                         /**< 参数数量 */
    } attrs;
    int value;
} attr;

在定义命令时,需要给定这些值,可以通过宏SHELL_CMD_PERMISSION(permission), SHELL_CMD_TYPE(type), SHELL_CMD_ENABLE_UNCHECKED, SHELL_CMD_DISABLE_RETURN, SHELL_CMD_READ_ONLY, SHELL_CMD_PARAM_NUM(num)快速声明

代理函数和代理参数解析

letter shell 3.x原生支持将整数,字符,字符串参数,以及在某些情况下的浮点参数直接传递给执行命令的函数,一般情况下,这几种参数类型完全可以满足调试需要,然而在某些情况下,用户确实需要传递其他类型的参数,此时,可以选择将命令定义成main函数形式,使用字符串传递参数,然后自行对参数进行解析,除此之外,letter shell还提供了代理函数的机制,可以对任意类型的参数进行自定义解析

关于代理函数的实现原理和具体使用示例,可以参考letter-shell代理函数解析

使用代理函数,用户需要自定义代理参数解析器,即一个将基本参数(整数,字符,字符串参数)转换成目标类型参数的函数或者宏,letter shell默认实现了浮点类型的参数解析器SHELL_PARAM_FLOAT(x)

然后,使用代理函数命令导出宏定义命令,比如需要需要传递多个浮点参数的函数,如下

c
void test(int a, float b, int c, float d)
{
    printf("%d, %f, %d, %f \r\n", a, b, c, d);
}
SHELL_EXPORT_CMD_AGENCY(SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
test, test, test,
p1, SHELL_PARAM_FLOAT(p2), p3, SHELL_PARAM_FLOAT(p4));

相比常规的命令导出,代理函数命令导出前4个参数和常规形式的命令导出一致,之后的参数即传递至目标函数的参数,letter shell默认实现的代理函数定义支持最多7个参数,p1~p7,对于不需要代理参数解析的参数,只需要对应写入px(x为1~7)即可,比如上方示例的p1和p3,而需要代理参数解析的参数,则需要使用对应的参数解析器,比如上方示例的p2和p4

函数签名

letter shell 3.2.x 之后,引入了函数签名的概念,以便于参数自动解析

之前的版本里,如果声明的命令是 SHELL_TYPE_CMD_FUNC,shell 会自动进行参数的转换,但是参数转换后的类型是猜出来的,无法保证转换后的数据类型是正确的,一旦猜错了,就容易导致程序挂掉

由此,借鉴 Java 等语言的函数签名,新版也引入了函数签名的概念,在声明命令时,可以给定最终执行命令的函数的签名,shell 根据这个签名进行参数转换,使用此功能时,需要打开宏 SHELL_USING_FUNC_SIGNATURE

函数签名是一个字符串,通过这个字符串声明表达函数的参数类型,返回值不声明,比如一个函数int func(int a, char *b, char c),它的函数签名就是 isc

基本类型的参数签名定义如下:

类型 签名
char(字符) c
char(数字) q
short(数字) h
int(数字) i
char * (字符串) s
pointer p

声明命令时,在最后添加一个参数 .data.cmd.signature = "isc" 即可,比如:

c
void shellFuncSignatureTest(int a, char *b, char c)
{
    printf("a = %d, b = %s, c = %c\r\n", a, b, c);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
funcSignatureTest, shellFuncSignatureTest, test function signature, .data.cmd.signature = "isc");

自定义类型解析

由于函数签名的引用,我们就可以使用函数签名描述任何参数,对应的,在参数类型已知的情况下,也可以定义对应的参数解析器进行参数解析,自定义的参数类型签名需要以 L 开头,以 ; 结尾,比如说定义一个 TestStruct 结构体类型为 LTestStruct;,那么接收这个结构体为参数的函数就可以通过这个类型签名定义函数签名,并导出命令

c
typedef struct {
    int a;
    char *b;
} TestStruct;

void shellParamParserTest(int a, TestStruct *data, char *

Issues· 0 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

C

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月17日
分类编程语言
定价开源

> 相关工具

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言