提供一个开源模块MiniShellEx
下载地址
https://github.com/MenglongWu/MiniShellEx
目前的版本是
V1.0-rc1
MiniShellEx是一个自定义命令解析模块,除了直接从键盘读取输入执行命令外,还提供其他方式执行命令(下面会解释,使用方法需要想象力)。
主要应用:
1. 该工程主要用于以Linux为平台的嵌入式设备,提供一种以命令行控制程序运行的方法,通常用于设备远程操控。
2. 有好的自动补全与命令层次关系,
免去记忆麻烦。如果有过
Cisco、华为等带网管功能的设备使用经验这一点不难理解,我在工程的Demo里有一个仿交换机控制台的工程
3. 分析配置脚本,并
执行脚本内容。
我在之前的项目用该模块调试与开发机房机架监控设备,随着项目的进行,本来的调试手段成了产品的后门。
本地与嵌入式端通过网络连接(TCP/IP、串口、USB),本地终端下输入命令,将命令以字符串形式发送到嵌入式设备,嵌入式设备执行后再反馈回来。
工程由来:
懒惰是再创造的火种。
1. 最初使用uboot的命令行调试程序,以及用uboot做裸机系统,对于小系统来说还算凑合,随着项目庞大后uboot的命令行越显力不从心。特别是当命令长度超过4个,系统可用命令有数十个之多时,有好的命令提示与
自动补全尤其有必要(uboot其实自带命令补全,不过发现时我已经用MiniShellEx实现,也就没继续深究)。
2. 命令太多时当我
忘记命令了,查阅help时会将数十个命令帮助都显示,
满屏的帮助不利于查阅,我希望有个
过滤功能。
3. help命令之你只能提供命令名的提示,而无法提供
参数提示。借鉴Cisco的用户体验,模仿它做了参数提示。这一点还是相当有用的,有时候项目开发数个月,有几个命令不那么常用,下次使用时记不起参数(我也不可能写个man page),通常都是查阅源代码,或者打印一张纸上写下命令调用方法。
工程采用
readline库作为依赖,要实现上面的功能(自动补全、命令历史)都不是上面难事。
使用举例:
1. 控制台或网络方式传递命令:
cmd1 argv1 argv2 argv3
想必不用多解释,与uboot一样cmd1是查询命令的简称,查找命令树里满足与cmd1匹配的命令则被调用。
int do_cmd1(void *ptr, int argc, char **argv);
2. 命令分组
输入?键提示当前可用命令的提升。当命令过多时特别占用屏幕。
cmd1 help 1
cmd2 help 2
...
cmdn help n
采用Cisco的分组方式后,命令被分开了,当命令个数在15个以内看起来比较舒服(帮助显示能保持在一屏以内)。
uboot里所有命令都集中在一个数组内,而MiniShellEx可以放在若干个数组里,查看帮助时只显示该数组里的内容,执行也仅限于该数组内的命令,两数组命令名简称相同并不会冲突,所以给命令起名字也不必加前缀。
当然分组也是有依据的,通常有个命令组作为根,其他命令组是根命令组的详细子集,或是其他命令组的子集,子集的层数可在源码里限定,默认拥有16(PROMPT_DEPTH)层子集
如根命令
boot_root有如下命令
nand
sd
ip
print
对于uboot的情况,如果要执行nand操作有下面指令
MiniShell>nand erase 0x100000 0x200000
MiniShell>nand write 0x20000000 0x100000 0x200000
MiniShell>nand read 0x20000000 0x100000 0x200000
而对于MiniShellEx你可以将命令分组,nand命令的第一个参数作为子集成员,也是每个命令的简称
boot_nand命令组有如下命令
erase
write
read
quit
此时按下?键查询帮助,查询道德是boot_nand组,其中quit命令用于回退到boot_root命令组,此时该命令组各命令的有效参数应该如下
MiniShell/nand >erase 0x100000 0x200000
MiniShell/nand >write 0x20000000 0x100000 0x200000
MiniShell/nand >read 0x20000000 0x100000 0x200000
上面的命令输入比uboot方式少输入几个字符,并且在输入命令忘记参数后,按?键对对后面的参数做提示
MiniShell/nand >erase
addr 擦除起始地址
all 擦除全部
MiniShell/nand >erase 0x100000
size 擦除大小
MiniShell/nand >erase 0x100000 0x200000
按回车,命令结束
加入sd命令也有一套与nand相类似的子集,上面说过,它们命令简称相同并不会引起冲突。
boot_sd命令组有如下命令
erase
write
read
quit
3. 读取并执行脚本
假如存在脚本
---------------------
# rewrite nand
[nand]
erase 0x100000 0x200000
write 0x20000000 0x100000 0x200000
# set network
[net]
ip = 192.168.1.3
gw = 192.168.1.1
mask = 255.255.255.0
---------------------
MiniShellEx默认分析字符串的方法是将字符串中的
" ,\t\n"几种字符作为参数分割符,为解析上面的脚本需要自定义分割字符
" ,\t\n[]=",即扩展"[]="三个字符。
将脚本文件“以单行读取,每行是一个命令”,分割后MiniShellEx看到的字符串应该是这样。
---------------------
# rewrite nand
nand
erase 0x100000 0x200000
write 0x20000000 0x100000 0x200000
# set network
net
ip 192.168.1.3
gw 192.168.1.1
mask 255.255.255.0
---------------------
其中第5行是空行,找不到任何命令所以不会执行;
第1、6行命令简称是 “#” 没有命令,所以不会被执行
我的MiniShellEx模块里有个msbuild工具,用于生产各组命令,生成它们的层次关系,尤其是命令参数提示,不然手动去编写这些数据结构相当累人。他需要编辑xml文件,本工程xml文件规则理应不该让用户去背、去手动编辑,后期会再做一个工具msedit由它去生成xml文件,同时做配置差错处理,例如
同一命令组内有命令简称冲突,两命令回调函数冲突,命令组命名冲突等,并提示用户修改。msedit采用ncurses库。
本帖最后由 lzwml 于 2016-6-12 20:31 编辑