网站首页 > 技术文章 正文
在我的自定义shell项目的这最后一部分中,我们将探索如何在解析后执行用户命令。此时,用户输入已成功分割成参数——现在是采取行动的时候了!
理解execute_command函数
这里的核心函数是:
void execute_command(char **args, int argc, Command *command, int command_count)
将用户输入与预定义命令匹配
执行相应的函数指针
如果没有匹配的命令则打印错误消息
让我们分解它
for (int i = 0; i < command_count; i++)
{
if (strcmp(args[0], command[i].name) == 0)
{
command[i].action(args, argc);
return;
}
}
printf("Unknown commnad: %s\n", args[0]);
1. 命令匹配: Shell遍历Command结构体数组,将输入与注册的命令名称进行比较。
2. 函数指针: 如果找到匹配项,通过指针调用相应的函数。
3. 错误反馈: 如果没有找到匹配项,shell通知用户命令未知(故意有个小拼写错误?)。
Command结构
每个命令都是一个看起来像这样的结构体:
typedef struct Command
{
char *name;
void (*action)(char **args, int argc);
} Command;
o name: 实际命令(如"say"或"date")
o action: 指向要执行的函数的指针
这种结构对于添加新命令非常方便,无需编写额外的if-else语句。
查看一些命令
让我们看看execute.c文件中实现的一些命令:
say_action
void say_action(char **args, int argc)
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
printf("%s ", args[i]);
}
}
printf("\n");
}
简单地回显用户输入的内容——一个很好的测试命令。
date_command
给你当前的日期和时间——根据标志如-dy、-dm等,可以选择性地分解为年、月、日、小时、分钟或秒。
clone_file_command
使用二进制读写将文件从一个位置复制到另一个位置。
cut_file_command
剪切文件(移动它)到新位置并删除原始文件——使用文件流和路径操作。
list_of_directory
以树状格式递归列出目录内容。真的很酷!
函数指针魔法
使用函数指针而不是条件语句使设计更具可扩展性。你可以像这样添加新命令:
{"new_command", new_command_action}
…并将其实现为常规函数。完成!
内存考虑
每个命令函数都接受char **args和int argc——就像main(int argc, char **argv)一样——保持熟悉和灵活。
另外,如主循环所示:
free_args(args, argc);
free(command);
每次命令执行后都会正确清理内存
为什么采用这种方法?
模块化设计: 每个命令都是自包含的,易于测试或扩展。
动态执行: 可以使用函数指针高效地分派命令。
用户友好的反馈: 优雅地处理无效输入。
可扩展结构: 在主文件中添加新命令只需要2行!
总结:构建自定义Shell
在过去的三部分中,我们用C构建了一个功能性的、模块化的shell:
o 第1部分: 动态读取用户输入
o 第2部分: 将输入解析为参数
o 第3部分(这一部分): 根据用户输入执行命令
猜你喜欢
- 2025-09-04 JAVA入门教程-第2章 基本编程概念
- 2025-09-04 C++基础语法梳理:算法丨十大排序算法(二)
- 2025-09-04 C语言段错误(Segmentation Fault)全面解析:原理、调试与预防
- 2025-09-04 山脊图——多组数据对比的好方法——R语言绘制
- 2025-09-04 编译器动手实践之:实现C语言函数定义的语法解析
- 2025-09-04 SOLIDWORKS语言切换:如何从英文切换到中文
- 2025-09-04 程序员上手 Rust 2 年后感悟:它的确强大,但想要取代 C 还远着呢
- 2025-09-04 我如何用C语言构建简单Shell (一)
- 2025-09-04 rust 每次发送请求时调用Arc::new(peer) 会影响性能吗?
- 2025-09-04 大语言模型学习Python中用__new__()创建实例
- 最近发表
-
- count(*)、count1(1)、count(主键)、count(字段) 哪个更快?
- 深入探索 Spring Boot3 中 MyBatis 的 association 标签用法
- js异步操作 Promise fetch API 带来的网络请求变革—仙盟创梦IDE
- HTTP状态码超详细说明_http 状态码有哪些
- 聊聊跨域的原理与解决方法_跨域解决方案及原理
- 告别懵圈!产品新人的接口文档轻松入门指南
- 在Javaweb中实现发送简单邮件_java web发布
- 优化必备基础:Oracle中常见的三种表连接方式
- Oracle常用工具使用 - AWR_oracle工具有哪些
- 搭载USB 3.1接口:msi 微星 发布 990FXA Gaming 游戏主板
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)