简单的CLI(command line interface)

2024-08-21 22:32

本文主要是介绍简单的CLI(command line interface),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、简介

        CLI(command line interface)是系统为用户提供的命令行接口。相信熟悉linux的同学肯定都必须了解一些linux的命令,在linux的shell上运行以实现一些功能。如最简单的ls命令,显示目录内容。

        CLI可以让用户实时的与系统进行交互,获取系统的实时信息,完成用户自定义的功能。所有的系统都必须为用户提供接口,只不过接口的形式多种多样,如web、传统的C/S结构的图像界面,当然CLI是其中的一种方式。

 

二、为什么要研究CLI

        你在做项目(主要指C/C++项目)的时候是否遇到过如下问题:

               1、程序运行过程中出现故障,想实时的查看一些运行状态;

               2、需要实时的与运行的系统进行一些简单的交互;

               3、遇到这些问题时,你又不想使用GDB跟踪;

 

        这时可以考虑为自己的程序增加一个小小的CLI,会极大的方便你的开发。

 

        问题来了,实现像linux 强大CLI系统,那可不是一件简单的事情。如果从零DIY一个自己的CLI感觉有点困难,这时软件复用就派上用场了。只要你可以找一个已有的项目,带CLI的将其移植一下,相信很快就可以为你的程序添加一个属于你自己私有的CLI。自定义一下命令,不需要华丽的用户体验,只要实用即可。

 

三、自己的CLI

        当时我想到的简单CLI就是uboot,熟悉uboot的同学肯定都知道uboot有一套命令集,如果做过uboot移植的同学肯定经常用它。只需要几个命令就可以将linux kernel引导起来,非常实用。那很自然的如果将uboot这套CLI移植到你的程序中,自定义一下适合自己的命令,那就大功告成了。

        那就废话少说,看看uboot源码,将CLI部分移植出来。

        下面是本人从uboot中移植的代码:

                1、很简单只有两个文件(command.h和command.c);

                2、将这两个文件编译一下:如gcc command.c -o ct,然后直接执行./ct;

                3、下面是测试结果

       源码:command.h

#ifndef __COMMAND_H__
#define __COMMAND_H__/* Monitor Command Prompt */
#define CONFIG_SYS_PROMPT "->"/* Buffer size for input from the Console */
#define CONFIG_SYS_CBSIZE		256#endif


 

       源码:command.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>#include "command.h"#define MAX_ARGC 10#define MAX_CMD_NUM 50uint8_t console_buffer[CONFIG_SYS_CBSIZE + 1];	/* console I/O buffer	*/
static char erase_seq[] = "\b \b";		/* erase sequence	*/
static char   tab_seq[] = "        ";		/* used to expand TABs	*/typedef void (*cmd_fun_t)(int , char *[])  ;
//命令结构体 
typedef struct CMD_STRUCT
{ char name[32]; /* Command Name */ char usage[64];/* Usage message */ cmd_fun_t CmdFun;//void (*CmdFun)(int , char *[]);/* Command execute function */ 
}CMD_STRUCT_T; int cmd_num_current = 0;//命令列表 
CMD_STRUCT_T CmdTbl[MAX_CMD_NUM]; #ifdef debug_cmd
#define debug_print() printf("[%s] line:%d\n", __FUNCTION__, __LINE__)
#else
#define debug_print() 
#endifvoid HelpCmdExeFun(int agrc, char *argv[])
{
debug_print() ;int i = 0;while (i < cmd_num_current){printf("%3d. %-32s -- %s\n", i, CmdTbl[i].name,  CmdTbl[i].usage);i++;}return; }void read_fun(int agrc, char * argv [ ])
{
debug_print() ;int i = 0;while (i < cmd_num_current) {if (read_fun == CmdTbl[i].CmdFun){printf("%s -- %s\n", CmdTbl[i].name,  CmdTbl[i].usage);break;}i++;}return; 
}void write_fun(int agrc, char * argv [ ])
{
debug_print() ;int i = 0;while (i < cmd_num_current) {if (write_fun == CmdTbl[i].CmdFun){printf("%s -- %s\n", CmdTbl[i].name,  CmdTbl[i].usage);break;}i++;}return; 
}void setenv_fun(int agrc, char * argv [ ])
{
debug_print() ;int i = 0;while (i < cmd_num_current) {if (setenv_fun == CmdTbl[i].CmdFun){printf("%s -- %s\n", CmdTbl[i].name,  CmdTbl[i].usage);break;}i++;}return; 
}int register_cmd(char *name, char *usage, cmd_fun_t fun)
{int ret;if (cmd_num_current < MAX_CMD_NUM){strcpy(CmdTbl[cmd_num_current].name, name);strcpy(CmdTbl[cmd_num_current].usage , usage);CmdTbl[cmd_num_current].CmdFun = fun;cmd_num_current++;}else{printf("%s error\n");return 1;}return 0;
}char parse_buf[256] ;
int parse_line(const char * const line, char *argv[])
{
debug_print();int argc = 0;char *ptr = parse_buf;memset(parse_buf, '\0', 256);strncpy(parse_buf, line, strlen(line));while ((argv[argc]=strtok(ptr, " "))!=NULL){
debug_print();
//printf("argv[%d]:%s\n", argc, argv[argc]);argc++;if (argc > MAX_ARGC)break;ptr = NULL;}
debug_print();return argc;
}static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
{char *s;if (*np == 0) {return (p);}if (*(--p) == '\t') {			/* will retype the whole line	*/while (*colp > plen) {puts (erase_seq);(*colp)--;}for (s=buffer; s<p; ++s) {if (*s == '\t') {puts (tab_seq+((*colp) & 07));*colp += 8 - ((*colp) & 07);} else {++(*colp);putc (*s, stdout );}}} else {puts (erase_seq);(*colp)--;}(*np)--;return (p);
}int32_t readline_into_buffer ( int8_t *const prompt, int8_t * buffer)
{int8_t *p = buffer;int8_t * p_buf = p;int32_t n = 0;				/* buffer index		*/int32_t plen = 0;			/* prompt length	*/int32_t col;				/* output column cnt	*/int8_t c;int8_t *ptr = prompt;/* print prompt */if (prompt) {plen = strlen (prompt);while (*ptr)putc(*ptr++, stdout);//puts (prompt);}col = plen;while (1){c = getc(stdin);/** Special character handling*/switch (c) {case '\r':				/* Enter		*/case '\n':*p = '\0';//puts ("\r");return (p - p_buf);case '\0':				/* nul			*/continue;case 0x03:				/* ^C - break		*/p_buf[0] = '\0';	/* discard input */return (-1);case 0x15:				/* ^U - erase line	*/while (col > plen) {puts (erase_seq);--col;}p = p_buf;n = 0;continue;case 0x17:				/* ^W - erase word	*/p=delete_char(p_buf, p, &col, &n, plen);while ((n > 0) && (*p != ' ')) {p=delete_char(p_buf, p, &col, &n, plen);}continue;case 0x08:				/* ^H  - backspace	*/case 0x7F:				/* DEL - backspace	*/p=delete_char(p_buf, p, &col, &n, plen);continue;default:/** Must be a normal character then*/if (n < CONFIG_SYS_CBSIZE-2){if (c == '\t') {	/* expand TABs		*///puts (tab_seq+(col&07));col += 8 - (col&07);} else{++col;		/* echo input		*///putc (c, stdout);}*p++ = c;++n;} else {			/* Buffer full		*/putc ('\a', stdout);}}}}int32_t readline ( int8_t *const prompt)
{/** If console_buffer isn't 0-length the user will be prompted to modify* it instead of entering it from scratch as desired.*/memset(console_buffer, '\0', CONFIG_SYS_CBSIZE+1);console_buffer[0] = '\0';return readline_into_buffer(prompt, console_buffer);
}int find_cmd(char *cmd)
{
debug_print();
//printf("cmd:%s\n",cmd);int cmd_index = 0;if (('0' == cmd[0]) && ('\0' == cmd[1]))return cmd_index;cmd_index = atoi(cmd);if ((cmd_index >0 ) && (cmd_index < cmd_num_current)){return cmd_index;}cmd_index = 0;while (cmd_index < MAX_CMD_NUM){if (0 == strncmp(CmdTbl[cmd_index].name, cmd, strlen(cmd)))return cmd_index;cmd_index++;}printf("Command  [%s ]  don't support!\n", cmd);debug_print();return -1 ;
}
/***************************************************************************** returns:*	1  - command executed, repeatable*	0  - command executed but not repeatable, interrupted commands are*	     always considered not repeatable*	-1 - not executed (unrecognized, bootd recursion or too many args)*           (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is*           considered unrecognized)** WARNING:** We must create a temporary copy of the command since the command we get* may be the result from getenv(), which returns a pointer directly to* the environment data, which may change magicly when the command we run* creates or modifies environment variables (like "bootp" does).*/
int run_command (const char * const cmd, int flag)
{
debug_print();//puts(cmd);int cmd_index = 0;int argc = 0;char *argv[MAX_ARGC];argc = parse_line(cmd, argv);if ((argc > 0) &&(argc < MAX_ARGC))cmd_index = find_cmd(argv[0]);elsereturn 1;if ( -1 != cmd_index)CmdTbl[cmd_index].CmdFun(argc, argv);debug_print();return 0;#if 0cmd_tbl_t *cmdtp;char cmdbuf[CONFIG_SYS_CBSIZE];	/* working copy of cmd		*/char *token;			/* start of token in cmdbuf	*/char *sep;			/* end of token (separator) in cmdbuf */char finaltoken[CONFIG_SYS_CBSIZE];char *str = cmdbuf;char *argv[CONFIG_SYS_MAXARGS + 1];	/* NULL terminated	*/int argc, inquotes;int repeatable = 1;int rc = 0;#ifdef DEBUG_PARSERprintf ("[RUN_COMMAND] cmd[%p]=\"", cmd);puts (cmd ? cmd : "NULL");	/* use puts - string may be loooong */puts ("\"\n");
#endifclear_ctrlc();		/* forget any previous Control C */if (!cmd || !*cmd) {return -1;	/* empty command */}if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {puts ("## Command too long!\n");return -1;}strcpy (cmdbuf, cmd);/* Process separators and check for invalid* repeatable commands*/#ifdef DEBUG_PARSERprintf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endifwhile (*str) {/** Find separator, or string end* Allow simple escape of ';' by writing "\;"*/for (inquotes = 0, sep = str; *sep; sep++) {if ((*sep=='\'') &&(*(sep-1) != '\\'))inquotes=!inquotes;if (!inquotes &&(*sep == ';') &&	/* separator		*/( sep != str) &&	/* past string start	*/(*(sep-1) != '\\'))	/* and NOT escaped	*/break;}/** Limit the token to data between separators*/token = str;if (*sep) {str = sep + 1;	/* start of command for next pass */*sep = '\0';}elsestr = sep;	/* no more commands for next pass */
#ifdef DEBUG_PARSERprintf ("token: \"%s\"\n", token);
#endif/* find macros in this token and replace them */process_macros (token, finaltoken);/* Extract arguments */if ((argc = parse_line (finaltoken, argv)) == 0) {rc = -1;	/* no command at all */continue;}/* Look up command in command table */if ((cmdtp = find_cmd(argv[0])) == NULL) {printf ("Unknown command '%s' - try 'help'\n", argv[0]);rc = -1;	/* give up after bad command */continue;}/* found - check max args */if (argc > cmdtp->maxargs) {cmd_usage(cmdtp);rc = -1;continue;}#if defined(CONFIG_CMD_BOOTD)/* avoid "bootd" recursion */if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSERprintf ("[%s]\n", finaltoken);
#endifif (flag & CMD_FLAG_BOOTD) {puts ("'bootd' recursion detected\n");rc = -1;continue;} else {flag |= CMD_FLAG_BOOTD;}}
#endif/* OK - call function to do the command */if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {rc = -1;}repeatable &= cmdtp->repeatable;/* Did the user stop this? */if (had_ctrlc ())return -1;	/* if stopped then not repeatable */}return rc ? rc : repeatable;#endif
}int main(int argc, char **argv)
{int32_t rc = -1;int32_t len;static int8_t lastcommand[CONFIG_SYS_CBSIZE] = { 0, };memset(CmdTbl, 0, sizeof(CMD_STRUCT_T)*MAX_CMD_NUM);register_cmd("help", "list all cmd\n\r",       HelpCmdExeFun);register_cmd("read", "read memory\n\r",    read_fun);register_cmd("write", "write memory\n\r",  write_fun);register_cmd("setenv", "set env\n\r",        setenv_fun);debug_print();while (1){len = readline (CONFIG_SYS_PROMPT);if (len > 0){memset(lastcommand, '\0', CONFIG_SYS_CBSIZE);strncpy (lastcommand, console_buffer, strlen(console_buffer));rc = run_command (lastcommand, 0);if (rc <= 0){/* invalid command or not repeatable, forget it */lastcommand[0] = 0;}}}return 0;
}


四、总结

        目的基本达到,实现了四个命令。

        这个小程序本身没有什么,但是从有实现简单CLI的想法,到寻找开源代码,最后移植调试。最关键的必须注重软件复用,现在的open source那么多,一定要学会好好利用。

 

这篇关于简单的CLI(command line interface)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1094462

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>

jenkins 插件执行shell命令时,提示“Command not found”处理方法

首先提示找不到“Command not found,可能我们第一反应是查看目标机器是否已支持该命令,不过如果相信能找到这里来的朋友估计遇到的跟我一样,其实目标机器是没有问题的通过一些远程工具执行shell命令是可以执行。奇怪的就是通过jenkinsSSH插件无法执行,经一番折腾各种搜索发现是jenkins没有加载/etc/profile导致。 【解决办法】: 需要在jenkins调用shell脚

JAVA用最简单的方法来构建一个高可用的服务端,提升系统可用性

一、什么是提升系统的高可用性 JAVA服务端,顾名思义就是23体验网为用户提供服务的。停工时间,就是不能向用户提供服务的时间。高可用,就是系统具有高度可用性,尽量减少停工时间。如何用最简单的方法来搭建一个高效率可用的服务端JAVA呢? 停工的原因一般有: 服务器故障。例如服务器宕机,服务器网络出现问题,机房或者机架出现问题等;访问量急剧上升,导致服务器压力过大导致访问量急剧上升的原因;时间和

简单的角色响应鼠标而移动

actor类 //处理移动距离,核心是找到角色坐标在世界坐标的向量的投影(x,y,z),然后在世界坐标中合成,此CC是在地面行走,所以Y轴投影始终置为0; using UnityEngine; using System.Collections; public class actor : MonoBehaviour { public float speed=0.1f; CharacterCo

docker-compose安装和简单使用

本文介绍docker-compose的安装和使用 新版docker已经默认安装了docker-compose 可以使用docker-compose -v 查看docker-compose版本 如果没有的话可以使用以下命令直接安装 sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-c