3922|3

222

帖子

2

TA的资源

一粒金砂(高级)

楼主
 

提供一个开源模块MiniShellEx [复制链接]

本帖最后由 lzwml 于 2016-6-12 20:31 编辑

提供一个开源模块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库。








最新回复

哇  谢谢分享    详情 回复 发表于 2016-6-13 09:44
点赞 关注

回复
举报

222

帖子

2

TA的资源

一粒金砂(高级)

沙发
 
 
 

回复

2万

帖子

74

TA的资源

管理员

板凳
 
哇  谢谢分享  
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

222

帖子

2

TA的资源

一粒金砂(高级)

4
 
本帖最后由 lzwml 于 2016-6-16 17:28 编辑
  1. #include <stdio.h>
  2. #include <minishell_core.h>

  3. extern struct cmd_prompt boot_root[];

  4. struct user_ptr
  5. {
  6.         char *name;
  7.         int a;
  8. };


  9. int main(int argc, char **argv)
  10. {
  11.         sh_whereboot(boot_root);

  12.         struct sh_detach_depth depth;
  13.         char *cmd[12];

  14.         depth.cmd = cmd;
  15.         depth.len = 12;
  16.         depth.seps = " \t";

  17.         struct user_ptr upt;
  18.         upt.name = "This is a minishell_core demo, modeled layer 3 Switch\n";
  19.         upt.a = 1001;

  20.        
  21.         sh_enter_ex(&depth, &upt);
  22.         return 0;
  23. }
复制代码





模块在使用msbuild生成层次关系后,main()里只用调用两个函数即可运行。
sh_whereboot告知从哪个命令分组开始作为根命令
sh_enter_ex启动MiniShellEx,等待用户输入。
其中depth是命令分割参数以及最大命令层数,
upt是用户传递给MiniShellEx的参数,被调用的命令处理代码do_xxx可以收到该参数
static int do_xxx(void *ptr, int argc, char **argv);
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表