一个在终端实现类Linux shell(cd ls命令)UI界面的项目(C语言实现)

2023-11-08

一个在终端实现类Linux shell(cd ls命令)UI界面的功能(C语言实现)

这2天做了一个类似Linux shell的UI界面,目前已初步完成cd, ls, help, pwd, quit等命令,在Linux下实现,效果图见下图:


ls命令:


开始及help命令:



对于完成此UI界面来说,最主要是根据输入的命令找到相关的命令处理函数。通过参考部分bash的实现,找到了如下方法:

通过一个回调函数指针,实现调用相关命令处理函数的功能,代码如下:

//*****************************************************************************
//
// Command line function callback type.
//
//*****************************************************************************
typedef int (*pfnCmdLine)(int argc, char *argv[]);

//*****************************************************************************
//
//! Structure for an entry in the command list table.
//
//*****************************************************************************
typedef struct
{
    //
    //! A pointer to a string containing the name of the command.
    //
    const char *pcCmd;

    //
    //! A function pointer to the implementation of the command.
    //
    pfnCmdLine pfnCmd;

    //
    //! A pointer to a string of brief help text for the command.
    //
    const char *pcHelp;
}
tCmdLineEntry;



而终端输入的命令最终会在CmdLineProcess()这个核心函数里面进行处理,代码如下:

int CmdLineProcess(char *pcCmdLine)
{
    static char *argv[CMDLINE_MAX_ARGS + 1];
    char *pcChar;
    int argc;
    int bFindArg = 1;
    tCmdLineEntry *pCmdEntry;

    //
    // Initialize the argument counter, and point to the beginning of the
    // command line string.
    //
    argc = 0;
    pcChar = pcCmdLine;

	
	//printf("CmdLineProcess: %s\n", pcCmdLine);
	
    //
    // Advance through the command line until a zero character is found.
    //
    while (*pcChar)
    {
        //
        // If there is a space, then replace it with a zero, and set the flag
        // to search for the next argument.
        //
        if(*pcChar == ' ')
        {
            *pcChar = 0;
            bFindArg = 1;
        }

        //
        // Otherwise it is not a space, so it must be a character that is part
        // of an argument.
        //
        else
        {
            //
            // If bFindArg is set, then that means we are looking for the start
            // of the next argument.
            //
            if(bFindArg)
            {
                //
                // As long as the maximum number of arguments has not been
                // reached, then save the pointer to the start of this new arg
                // in the argv array, and increment the count of args, argc.
                //
                if(argc < CMDLINE_MAX_ARGS)
                {
					//printf("\nargc=%d, argv=%s ", argc, argv);
					//printf("   pcChar=%c ", *pcChar);
					
                    argv[argc] = pcChar;
					
					//printf("\nargc=%d, argv=%s ", argc, argv);
					
                    argc++;
                    bFindArg = 0;
                }

                //
                // The maximum number of arguments has been reached so return
                // the error.
                //
                else
                {
                    return(CMDLINE_TOO_MANY_ARGS);
                }
            }
        }

        //
        // Advance to the next character in the command line.
        //
        pcChar++;
    }

	
	//printf("argc=%d, argv=%s ", argc, argv);
	
    //
    // If one or more arguments was found, then process the command.
    //
    if(argc)
    {
        //
        // Start at the beginning of the command table, to look for a matching
        // command.
        //
        pCmdEntry = &g_sCmdTable[0];
		
		//printf("pCmdEntry->pcCmd=%s \n", pCmdEntry->pcCmd);

        //
        // Search through the command table until a null command string is
        // found, which marks the end of the table.
        //
        while(pCmdEntry->pcCmd)
        {
			//printf("while: pCmdEntry->pcCmd=%s, argv[0]=%s \n", pCmdEntry->pcCmd, argv[0]);
			//printf("while: pCmdEntry->pfnCmd=0x%x \n", pCmdEntry->pfnCmd);		
		
            //
            // If this command entry command string matches argv[0], then call
            // the function for this command, passing the command line
            // arguments.
            //
            if(!strcmp(argv[0], pCmdEntry->pcCmd))
            {
				//printf("Define: pCmdEntry->pcCmd=%s, argv[0]=%s \n", pCmdEntry->pcCmd, argv[0]);
				//printf("***pCmdEntry->pfnCmd=0x%x \n", pCmdEntry->pfnCmd);
				
                return(pCmdEntry->pfnCmd(argc, argv));
            }

            //
            // Not found, so advance to the next entry.
            //
            pCmdEntry++;
        }
    }

    //
    // Fall through to here means that no matching command was found, so return
    // an error.
    //
    return(CMDLINE_BAD_CMD);
}


参考了部分网上的资料,实现Linux "ls" 命令的源码如下:

/************************************************************************************
** File: - Z:\work\code\c\longluo\cmd_ls.c
** VENDOR_EDIT
** Copyright (C), tcpipstack.
** 
** Description: 
**      cmd_ls.c - The implement of the Linux Like "ls" command.
** 
** Version: 1.0
** Date created: 10:20:56,14/11/2012
** Author: long.luo
** 
** --------------------------- Revision History: --------------------------------
** 	<author>	<data>			<desc>
** 
************************************************************************************/

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <dirent.h>

int do_ls(char *dir,char *filename,int lflag)
{
	int n;
	struct stat buf;
	char out[100];
	struct passwd *pw;
	struct group *gr;
	struct tm *t;

    //如果不带l参数,直接显示文件/目录名
	if (lflag == 0)		
	{
		printf("%s\t", filename);
		return 0;
	}
		
	if(lstat(dir,&buf)<0)
	{
		fprintf(stderr,"stat error:%s\n",strerror(errno));
		return -1;
	}

    //获取字符串的属性:普通文件-、目录d、字符设备c、块设备b、
    //管道文件p、连接文件l、套接字文件s
	switch(buf.st_mode & S_IFMT)		
	{
	case S_IFREG:	
		printf("-");
		break;
	case S_IFDIR:	
		printf("d");
		break;
	case S_IFCHR:	
		printf("c");
		break;
	case S_IFBLK:	
		printf("b");
		break;
	case S_IFIFO:	
		printf("p");
		break;
	case S_IFLNK:	
		printf("l");
		break;
	case S_IFSOCK:	
		printf("s");
		break;
	}

    //打印文件的读写属性:读r、写w、执行x、无权限-
	for(n=8;n>=0;n--)		
	{
		if(buf.st_mode&(1<<n))
		{
			switch(n%3)
			{
			case 2:
				printf("r");
				break;
			case 1:
				printf("w");
				break;
			case 0:
				printf("x");
					break;
			default:
				break;
			}
		}
		else
		{
			printf("-");
		}
	}

	//硬链接数,此链接非彼链接,指(包含)目录的个数,
	//文件为1,目录起始为2,再加上目录里包含的目录个数(不递归,只一层)
	printf(" %d",buf.st_nlink);		
	
	pw = getpwuid(buf.st_uid);		//所属用户名
	printf(" %s",pw->pw_name);		

	gr = getgrgid(buf.st_gid);		//所属组名
	printf(" %s",gr->gr_name);

	printf(" %ld",buf.st_size);		//字节计总大小

	t = localtime(&buf.st_atime);	//最后一次访问时间
	printf(" %d-%d-%d %d:%d"
		,t->tm_year+1900
		,t->tm_mon+1
		,t->tm_mday
		,t->tm_hour
		,t->tm_min);
   	printf(" %s ",filename);	

	//判断是否为链接,是返回真   
	if(S_ISLNK(buf.st_mode))		
	{
		printf(" -> ");
		if(readlink(filename,out,100)==-1)
		{
			//printf("readlink error\n");
		}
		printf("%s",out);
	}
	printf("\n");
	
	return 0;
}


// ls的准备工作
int ls_prepare(char *w,int aflag,int lflag)		
{
	struct stat buf;		//man lstat可以看到此结构
	char name[100];	
	DIR *dir;		//类似打开文件的fd描述符
	struct dirent *pdr;		//man readdir可以看到此结构

    //获取文件/目录属性并赋值给buf,该函数和lstat一样,
    //只是当w为链接时,指代他本身,并不存在文件
	if(lstat(w,&buf)<0)		
	{
		fprintf(stderr,"stat error:%s\n",strerror(errno));
		return -1;
	}
	
	if(S_ISDIR(buf.st_mode))	//判断是否为目录,是返回真
	{
		dir = opendir(w);		//打开目录
		while ((pdr = readdir(dir))!=NULL)	//读/遍历目录
		{
			if(aflag==0)	//如果不带a参数,越过以.开头的所有文件/目录
			{ 
				if(pdr->d_name[0]=='.')
					continue;
				memset(name,0,100);		
				strcpy(name,w);			//拷贝
				strcat(name,"/");		//追加
				strcat(name,pdr->d_name);
				do_ls(name,pdr->d_name,lflag);
			}
			//有a参数显示所有
			else		
			{
				memset(name,0,100);
				strcpy(name,w);
				strcat(name,"/");
				strcat(name,pdr->d_name);
				do_ls(name,pdr->d_name,lflag);
			}
		}
		closedir(dir);
	}
	//为文件则直接显示
	else	
	{
		do_ls(w,w,lflag);
	}
	
	return 0;
}


项目的main函数代码如下,主要就是一个while(1)循环读取终端的输入,然后送入命令处理函数,值得注意的是因为输入了换行符,因此需要对输入的字符进行处理,否则会有bug产生:

int main(int argc, char *argv[])
{
    int nStatus, nStrLen;
	
	fprintf(stderr, "Hello, CMD UI Program...");
	
    // Enter an infinite loop for reading and processing commands from the user.
    while (1) {
        // Print a prompt to the console. Show the CWD.
        printf("\n%s> ", g_cCwdBuf);

        // Get a line of text from the user.
        fgets(g_cCmdBuf, CMD_BUF_SIZE, stdin);

        // Remove the char '\n'.
		nStrLen = strlen(g_cCmdBuf);
		if ('\n' == g_cCmdBuf[nStrLen - 1]) {
			g_cCmdBuf[nStrLen - 1] = '\0';
		}
			
        // Pass the line from the user to the command processor.
        // It will be parsed and valid commands executed.
        nStatus = CmdLineProcess(g_cCmdBuf);

        // Handle the case of bad command.
        if(nStatus == CMDLINE_BAD_CMD) {
			printf("Bad command!\n");
        }
        // Handle the case of too many arguments.
        else if(nStatus == CMDLINE_TOO_MANY_ARGS) {
			printf("Too many arguments for command processor!\n");
        }
        // Otherwise the command was executed. Print the error
        // code if one was returned.
        else if(nStatus != 0) {
			printf("Command returned error code.\n");
        }
    }
	
	return 0;
}


在编写这个小项目的同时,也顺便把Makefile的编写也复习了下,这个项目的Makefile文件如下:

#
# Makefile - Rules for building the program.
#	
#	History:
#		long.luo, 12/11/2012, created it.
#		long.luo, 13/11/2012, modified it.
#


# The compiler to be used.
ifndef COMPILER
COMPILER=gcc
endif

# Definitions for using GCC.
ifeq (${COMPILER}, gcc)

# The command for calling the compiler.
CC=gcc

# The flags passed to the compiler.
CFLAGS=-Wall -Os -c

# The command for calling the linker.
LD=ld

# The flags passed to the linker.
LDFLAGS=--gc-sections

# The PHONY targets.	
.PHONY: all clean

# The default rule, which causes the Application to be built.
all: cmd_ui

# The rule to create the target directory.
${COMPILER}:
	mkdir ${COMPILER}

# The rule for building the object file from each C source file.
%.o : %.c
	${CC} ${CFLAGS} -D${COMPILER} -o $@ $<

# The objects.
OBJS=cmdline.o cmd_ui_shell.o cmd_ls.o

# The final executable file.
exec=cmd_ui
	
# The rule for building the application.
cmd_ui: ${OBJS}
	$(CC) -o $@ $?

# The rule to clean out all the build products.
clean:
	rm -f ${wildcard *.o} ${exec}	
	
endif


以上,这个项目可以应用在其他终端上,比如串口上实现简单的UI界面:-)


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个在终端实现类Linux shell(cd ls命令)UI界面的项目(C语言实现) 的相关文章

  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • SSH 主机密钥指纹与模式 C# WinSCP 不匹配

    我尝试通过 WinSCP 使用 C 连接到 FTPS 服务器 但收到此错误 SSH 主机密钥指纹 与模式不匹配 经过大量研究 我相信这与密钥的长度有关 当使用 服务器和协议信息 下的界面进行连接时 我从 WinSCP 获得的密钥是xx xx
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 如何针对 Nancy 中的 Active Directory 进行身份验证?

    这是一篇过时的文章 但是http msdn microsoft com en us library ff650308 aspx paght000026 step3 http msdn microsoft com en us library
  • PHP 日志文件颜色

    我正在编写一个 PHP 日志文件类 但我想为写入文件的行添加颜色 我遇到的问题是颜色也会改变终端的颜色 我想要实现的是仅更改写入日志文件的行的颜色 class logClass extends Singleton private funct
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 为什么模板不能位于外部“C”块内?

    这是一个后续问题一个答案 https stackoverflow com questions 4866433 is it possible to typedef a pointer to extern c function type wit
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • 我的 strlcpy 版本

    海湾合作委员会 4 4 4 c89 我的程序做了很多字符串处理 我不想使用 strncpy 因为它不会终止 我不能使用 strlcpy 因为它不可移植 只是几个问题 我怎样才能让我的函数正常运行 以确保它完全安全稳定 单元测试 这对于生产来
  • 初始化变量的不同方式

    在 C 中初始化变量有多种方法 int z 3 与 int 相同z 3 Is int z z 3 same as int z z 3 您可以使用 int z z 3 Or just int z 3 Or int z 3 Or int z i
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 如何构建印度尼西亚电话号码正则表达式

    这些是一些印度尼西亚的电话号码 08xxxxxxxxx 至少包含 11 个字符长度 08xxxxxxxxxxx 始终以 08 开头 我发现这个很有用 Regex regex new Regex 08 0 9 0 9 0 9 0 9 0 9
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • Bing 地图运行时错误 Windows 8.1

    当我运行带有 Bing Map 集成的 Windows 8 1 应用程序时 出现以下错误 Windows UI Xaml Markup XamlParseException 类型的异常 发生在 DistanceApp exe 中 但未在用户
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr
  • php56 - CentOS - Remi 仓库

    我刚刚在测试盒上安装了 php 5 6 正常的 cli php 解释器似乎不存在 gt php v bash php command not found gt php56 v PHP 5 6 13 cli built Sep 3 2015
  • 如何连接字符串和常量字符?

    我需要将 hello world 放入c中 我怎样才能做到这一点 string a hello const char b world const char C string a hello const char b world a b co

随机推荐

  • 精准测试之过程与实践

    作者 京东工业 宛煜昕 一 怎样的技术 百度百科 精准测试是一套计算机测试辅助分析系统 精准测试的核心组件包含的软件测试示波器 用例和代码的双向追溯 智能回归测试用例选取 覆盖率分析 缺陷定位 测试用例聚类分析 测试用例自动生成系统 这些功
  • image caption问题为什么需要spatial attention

    参考论文 SCA CNN Spatial and Channel wise Attention in Convolutional Networks for Image Captioning image caption是一个image to
  • android 经纬度 谷歌,android:GPS获取location经纬度并用谷歌解析为地理位置名称

    实现的功能 先获取本地的经纬度 再根据经纬度 请求googleapis来解析地理位置名称 下面的例子 能够跑起来 亲测 多说无益 看码 首先搞一个布局 其实就是一个textView 一个button 点击button后 在textview展
  • python3 赋值列表sort打印出None的解决方法

    d 42 62 78 19 13 53 67 35 sort print d d 42 62 78 19 13 53 67 35 print d sort 结果如下 None None 列表创建了之后 执行列表排序 不在变量里排序 因为so
  • python 大学排行网站全部排行数据

    RANKINGS CRAWLER 中国大学排名 中国两岸四地排名 全球体育类院系大学排行 世界大学学术排名 中国最好学科排名 中国大学专业排名 世界一流学科排名 每个专业学科排行都有 方法跟实际代码有变动 方法一 获取中国大学排名 中国两岸
  • js逆向-某市公共资源交易网

    目标网站首页 aHR0cDovL2dnenkuendmd2IudGouZ292LmNu 分析页面 aHR0cDovL2dnenkuendmd2IudGouZ292LmNuL3h3engvaW5kZXhfMi5qaHRtbA 话不多说 开始今
  • 使用systemctl命令启动和关闭mysql

    以前都用service命令管理mysql 现在liunx系统升级了 又有了新的更好的方法管理系统进程 现在我们来学习如何用systemctl命令管理mysql Systemctl是一个systemd工具 主要负责控制systemd系统和服务
  • P5367 【模板】康托展开【树状数组优化】

    题目链接 include
  • DCIC-A城市巡游车与网约车运营特征对比分析-2-可视化

    接前述 数据读取 上次遗留下两个问题 1 该案例的数据集过多 如果每次读一个数据的部分行 比如10000行 那在拼接所有数据集的时候也是每个数据只读10000行吗 回答 虽然我们通过更改数据类型 使得原始数据的大小有所改变 但如果想要把所有
  • 人工智能数据标注案例之人脸识别案例

    人工智能是未来的发展趋势 人脸识别是人工智能应用最为广泛的一项技术 在现实生活中 我们使用的支付宝 微信的安全验证 智能手机的人脸解锁功能等都运用到了人脸识别 作为人工智能发展的三大要素之一 数据的作用不可小觑 其中数据采集与数据标注是数据
  • MATLAB图像识别技术在棉花叶面病虫害识别上的

    MATLAB图像识别技术在棉花叶面病虫害识别上的应用 摘 要 棉花是新疆地区种植最为广泛的经济作物 利用MATLAB图像识别技术将相机采集到的患病棉花叶面经过图像灰度化 图像增强 图像二值化 图像形态学处理 图像填充 图像分割等预处理后用函
  • C语言数组第十课---------------三子棋-------数组经典练手题

    作者前言 作者介绍 作者id 老秦包你会 简单介绍 喜欢学习C语言和python等编程语言 是一位爱分享的博主 有兴趣的小可爱可以来互讨 个人主页 小小页面 gitee页面 秦大大
  • 使用MATLAB GUI实现运动目标追踪

    使用MATLAB GUI实现运动目标追踪 物体追踪是计算机视觉中的一个重要研究领域 它可以应用于自动驾驶 智能监控等多个领域 本篇文章将介绍如何使用MATLAB GUI实现运动目标的追踪 并给出相应的源代码 前置知识 在开始之前需要掌握以下
  • 程序静态分析第一课

    程序静态分析第一课 该课程主要内容来自北京大学熊英飞老师的 软件分析技术 事例一 飞机为了保证飞行安全 在很多设备上会设置冗余设备 一般来说都是一主二备三应急 一架飞机上同样功能的设备设施 会安装起码三套或更多来应付其中一套出故障而导致飞机
  • pe中怎么卸载服务器系统更新,如何卸载win7系统更新用pe装win7

    缺省设置 724 512M物理内存 改变命令 代码如下 sysctl w vm vfs cache pressure 200 sysctl w vm min free kbytes 1024 通过本次的分享我们在使用参数优化的时候遇到的问题
  • html标签(下)----常用高级标签

    下列代码可直接运行 br br br br br 空 nbsp nbsp nbsp 格 div style width 400px height 60px background color darkgrey div
  • Oracle锁机制

    增删改查中查询不需要锁 即使数据被锁定也能在还原信息中查询出锁定之前的值 其余三项均会使用行级锁 直到用户commit或rollbak 锁是在指定语句的最低可能级别自动获取的 增删改获取行级锁而不是块级或表级 修改对象 如移动表 会获取对象
  • 朝代官制,6部是什么

    六部 六部就是我们所熟知的 吏 户 礼 兵 刑 工 它是隋唐以来中央行政机构中的重要一极 隋唐开创的三省六部制最早可以追溯至西周时期 但史料对此记载颇少 当时相应的中央行政机构所管辖的职能远远没有后世开创的六部职能完善 秦朝开创了三公九卿制
  • 星际争霸2神族全兵种介绍

    星际争霸2神族全兵种介绍 貌似很多兵种啊 而且根据目前的demo 兵种相克非常明显的话游戏节奏可能变慢 不知道可玩性会不会像1那么高 星际2神族全兵种公布 2007 6 18 作者 OGame NeT Sodoes 更多精彩尽在神州论坛 翻
  • 一个在终端实现类Linux shell(cd ls命令)UI界面的项目(C语言实现)

    一个在终端实现类Linux shell cd ls命令 UI界面的功能 C语言实现 这2天做了一个类似Linux shell的UI界面 目前已初步完成cd ls help pwd quit等命令 在Linux下实现 效果图见下图 ls命令