ctshell
=======
.. image:: https://img.shields.io/github/license/MDLZCOOL/ctshell
:target: https://github.com/MDLZCOOL/ctshell/blob/main/LICENSE
:alt: license
Ctshell 是一款小而美的、低开销的shell,专为资源受限的嵌入式系统而设计。
特性
-------
* 命令补全:支持使用 TAB 键自动补全命令。
* 命令历史记录:支持使用向上 (↑) 和向下 (↓) 箭头键浏览历史记录。
* 行编辑:支持光标移动(左/右)、退格键处理以及在行内任意位置插入文本。
* 环境变量:支持设置、取消设置、列出变量,并使用“$”前缀进行内联扩展。
* 非阻塞架构:输入和处理过程解耦,使其兼容裸机和实时操作系统环境。
* 信号处理 (SIGINT):实现 setjmp/longjmp 逻辑,可通过 Ctrl+C 中断长时间运行的命令。
* 内置参数解析器:包含一个强类型参数解析器,可轻松处理自定义命令中的标志(布尔值)、整数、字符串和子命令。
* ANSI 转义序列支持:处理用于箭头键和屏幕控制的标准 VT100/ANSI 转义码。
* 文件系统支持:目前已原生支持 FatFS,其他文件系统的原生支持也将很快推出。
* 命令层级框架:支持层级式命令管理。
移植
-------
Ctshell 易于移植——它提供了针对多种主流嵌入式平台的原生移植实现,基本无需额外配置即可使用。
更多详情,请参阅相关文档。
Demo
-------
Ctshell 提供直观的交互体验,其核心功能演示如下:
**查看所有可用命令**
使用 ``help`` 命令可以快速列出所有可用命令及其简要说明。
.. image:: ../assets/help.png
**调试嵌入式系统**
将ctshell集成到您的嵌入式项目中,可以快速调试外设/模块的状态。
.. image:: ../assets/demo_ina226.png
**操作环境变量**
使用 ``set``/``unset`` 命令灵活管理环境变量,并使用 ``$`` 前缀展开变量。
.. image:: ../assets/variables.png
**Abort Long-running Commands**
使用 ``Ctrl+C``(SIGINT)可以立即终止死循环/长时间运行的命令,而不会导致系统崩溃。
.. image:: ../assets/sigint.png
基本用法
-------
本部分仅介绍自定义命令的基本用法(不涉及端口细节)。实现过程只需两个关键步骤:实现自定义命令函数,并使用一个宏导出该命令。Ctshell 会自动处理底层工作,例如命令注册、列表维护和参数解析。
以下将以INA226电源监控器驱动程序的命令开发为例,全面演示如何使用子命令和多种类型参数来实现复杂命令,这是ctshell命令在嵌入式开发中最典型的使用场景。
.. code-block:: c
#include "ctshell.h"
int cmd_ina226(int argc, char *argv[]) {
if (argc < 2) {
ina226_print_usage();
return 0;
}
// 初始化ctshell参数解析器
ctshell_arg_parser_t parser;
ctshell_args_init(&parser, argc, argv);
// 声明预期的子命令
ctshell_expect_verb(&parser, "start");
ctshell_expect_verb(&parser, "stop");
ctshell_expect_verb(&parser, "status");
// 声明预期参数,这些参数必须是强类型化的,格式为(解析器、短选项、参数别名)
// 参数别名用于后续的值检索
ctshell_expect_int(&parser, "-b", "bus");
ctshell_expect_int(&parser, "-a", "addr");
ctshell_expect_int(&parser, "-t", "battery_idx");
ctshell_expect_bool(&parser, "-f", "keep_running");
// 执行参数解析,底层会自动验证参数类型和格式,无需手动处理
ctshell_args_parse(&parser);
// 根据子命令/参数执行业务逻辑
// ctshell_has:检查是否传入了指定的子命令/参数
// ctshell_get_*: 获取参数值
if (ctshell_has(&parser, "start")) {
int bus = ctshell_has(&parser, "bus") ? ctshell_get_int(&parser, "bus") : INA226_DEFAULT_BUS;
int addr = ctshell_has(&parser, "addr") ? ctshell_get_int(&parser, "addr") : INA226_DEFAULT_ADDR;
int bat_idx = ctshell_has(&parser, "battery_idx") ? ctshell_get_int(&parser, "battery_idx") : 1;
int force = ctshell_get_bool(&parser, "keep_running");
return ina226_start(bus, addr, bat_idx, force);
} else if (ctshell_has(&parser, "stop")) {
return ina226_stop();
} else if (ctshell_has(&parser, "status")) {
return ina226_status();
} else {
ina226_print_usage();
}
return 0;
}
// 使用单个宏导出命令,ctshell 会自动注册,无需手动维护命令列表
// 宏参数:<命令名称> <命令功能> <命令描述>
CTSHELL_EXPORT_CMD(ina226, cmd_ina226, "INA226 power monitor driver");
命令注册后,即可在ctshell终端中以任意参数顺序交互式地使用该命令。以下是上面提到的 ``ina226`` 命令的实际调用方法:
.. code-block:: shell
# 启动 INA226:使用默认的 I2C 总线/地址,电池索引为 2,启用连续运行模式
ina226 start -t 2 -f
# 启动 INA226:指定 I2C 总线 1,设备地址为 0x40,其他参数使用默认值
ina226 start -b 1 -a 64 # 十进制数 64 对应十六进制数 0x40,ctshell 原生支持十进制/十六进制输入。
# 停止 INA226 数据采集
ina226 stop
# 查看 INA226 的当前工作状态
ina226 status
# 查看命令用法
ina226
正如您所见,ctshell 为嵌入式 shell 的使用提供了流畅的交互体验。它为用户提供了直观的调用流程,学习曲线平缓,心智负担较低。
文档
-------
参见 `ctshell Documentation `_。
许可
-------
Copyright 2026 MDLZCOOL.
根据 `Apache 2.0 许可证 `_ 的条款分发。
.. toctree::
:maxdepth: 1
:caption: 快速开始
quickstart/porting
.. toctree::
:maxdepth: 1
:caption: API 参考手册
api/api