主函数运行要去读取从标准输入或终端上输入的整个命令行,然后再去解析命令行参数,解析出来之后,要将其封装成一个 program,然后再将 program 放入 job 中,然后再去执行 job 中的命令行的内容。

17.1 job.o

  job.h 文件

 #ifndef __JOB_H__
#define __JOB_H__ typedef struct
{
char **args; //shell 当中输入的命令参数;对应主函数中的 char *argv[] 参数
}Program; //作业结构体,表示若干个要执行的参数
typedef struct
{
char *cmd;
int progs_num;
Program *progs;//Program 的结构体指针
}Job; extern Job * create_job(char *cmd);
extern void destroy_job(Job *job);
extern Program* create_program(char **arg);//创建一个程序
extern void destroy_program(Program *prog);
extern int add_program(Job *job, Program *prog);//将程序加入到 job 中 #endif

  job.c 文件

 #include "job.h"
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <memory.h> /* 根据 commond 命令创建 job */
Job * create_job(char *cmd)
{
Job *job = (Job *)malloc(sizeof(Job));
assert(job != NULL); job->cmd = (char *)malloc(sizeof(char) * strlen(cmd));
assert(job->cmd != NULL); strcpy(job->cmd, cmd);
job->progs_num = ;
job->progs = NULL; return job;
} void destroy_job(Job *job)
{
assert(job != NULL);
free(job->progs);
free(job->cmd);
free(job);
} /* 统计命令行参数的个数 */
static int arg_num(char **arg)
{
int i = ;
char *start = arg[]; while(start != NULL) {
i++;
start = arg[i];
} return i;
} /*
* 函数功能: 构建一个 program
* 函数参数:
* @arg:命令行传入的参数
* 返回值:
*/
Program* create_program(char **arg)//创建一个程序
{
//在堆当中创建 program 内存块
Program *prog = (Program *)malloc(sizeof(Program));
assert(prog != NULL); int counter = arg_num(arg); //多 new 一个空间存放 NULL ,所以 counter 要 +1
prog->args = (char **)calloc(counter + , sizeof(char *)); int i;
for(i = ; i < counter; i++) {
int len = strlen(arg[i]);
prog->args[i] = (char *)malloc(len);
assert(prog->args[i] != NULL);
strcpy(prog->args[i], arg[i]);
}
prog->args[i] = NULL;
return prog;
} void destroy_program(Program *prog)
{
assert(prog != NULL);
int i = ; /* 命令行释放 */
while(prog->args[i] != NULL) {
free(prog->args[i]);
i++;
}
free(prog->args);//数组释放
free(prog);
} /* 1.通过动态分配创建一个结构体数组
* 2.将 job 中原先的 progs 复制给 ps 结构体数组
* 3.在向 ps 结构体数组中加上新的 prog
* 4.把 job 中原先的 progs 释放掉
* 5.将 job 中的 progs 指向 ps
*/
int add_program(Job *job, Program *prog)//将程序加入到 job 中
{
Program *ps = (Program *)malloc(sizeof(Program) * (job->progs_num + ));//1 为NULL的初始化 memcpy(ps, job->progs, job->progs_num * sizeof(Program));
ps[job->progs_num++] = *prog;
free(job->progs);
job->progs = ps;
}

  编译成 .o 文件

  gcc -o obj/job.o -Iinclude -c src/job.c

17.2 命令行参数的解析

17.2.1 主函数

  mshell.c

 #include "job.h"
#include "cmd_func.h"
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <assert.h>
#include <malloc.h> /* shell 中的提示符 */
char *prompt = "mshell > "; /* 指定命令行中传递的最大命令行的长度 */
#define MAX_COMMAND_LEN 256 /* 对命令行进行解析 */
void parse_cmd(Job *job, char *line)
{
char **args = (char **)malloc( * sizeof(char *));//创建的 program 里面的args
assert(args != NULL); /* 分割命令行 */
char *cmd = strtok(line, " ");
args[] = (char *)malloc(strlen(cmd) * sizeof(char)); //第一个参数为命令本身
strcpy(args[], cmd); int i = ;
char *s;
while((s = strtok(NULL, " ")) != NULL) {
args[i] = (char *)malloc(strlen(s) * sizeof(char));
strcpy(args[i], s);
i++;
} //根据 args 创建 program
Program * prog = create_program(args);
add_program(job, prog); int j;
for(j = ; j < i; j++) {
free(args[j]);
} free(args);
} /* 执行命令 */
void excute_cmd(Job *job)
{
int i;
for(i = ; i < job->progs_num; i++) {
if(!strcmp(job->progs[i].args[], "cd")) {
cd_func(&job->progs[i]);
return;
} if(!strcmp(job->progs[i].args[], "pwd")) {
pwd_func(&job->progs[i]);
return;
} if(!strcmp(job->progs[i].args[], "exit")) {
exit_func(&job->progs[i]);
return;
}
}
} int main(int argc, char *argv[])
{
char buff[MAX_COMMAND_LEN];//存放从命令行中输入的整个命令行
memset(buff, , MAX_COMMAND_LEN);
ssize_t size = strlen(prompt) * sizeof(char);//提示符占用的总的大小 write(STDOUT_FILENO, prompt, size);//输出 shell 的提示符 ssize_t len;
while() {
/* 从标准输入读取命令行的内容 */
len = read(STDIN_FILENO, buff, MAX_COMMAND_LEN);
buff[len - ] = ; //结束符 if(strlen(buff) > ) {//命令行要大于0
Job *job = create_job(buff);//创建 job parse_cmd(job, buff); //对命令行进行解析 excute_cmd(job); // 执行命令
destroy_job(job); // 销毁 } write(STDOUT_FILENO, prompt, size);
memset(buff, , MAX_COMMAND_LEN);
} return ;
}

17.2.2 命令功能函数

  cmd_func.h

 #ifndef __CMD_FUNC_H__
#define __CMD_FUNC_H__ #include "job.h" #define BUFF_SIZE_256 256 extern void cd_func(Program *prog);
extern void pwd_func(Program *prog);
extern void exit_func(Program *prog); #endif

  cmd_func.c

 #include "cmd_func.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "job.h"
#include <fcntl.h>
#include <string.h>
#include <unistd.h> /* 切换目录 */
void cd_func(Program *prog)
{
if(chdir(prog->args[]) < ) {
perror("cd error");
}
} /* 显示当前工作目录路径 */
void pwd_func(Program *prog)
{
char buff[];
memset(buff, , sizeof(buff)); /* 获取当前工作目录的绝对路径 */
if(getcwd(buff, sizeof(buff)) == NULL) {
perror("pwd error");
} printf("%s\n", buff);
} /* 退出 */
void exit_func(Program *prog)
{
exit();
}

  编译成.o 文件

  gcc -o obj/cmd_func.o -Iinclude -c src/cmd_func.c

17.3 编译调试  

  gcc -o bin/mshell -Iinclude obj/*.o src/mshell.c

  

十七、文件和目录——minishell(1)的更多相关文章

  1. CentOS(十)--与Linux文件和目录管理相关的一些重要命令②

    在结束了第二期的广交会实习之后,又迎来了几天休闲的日子,继续学习Linux.在上一篇随笔 Linux学习之CentOS(十七)--与Linux文件和目录管理相关的一些重要命令① 中,详细记录了与Lin ...

  2. 【转】第七章、Linux 文件与目录管理

    原文网址:http://vbird.dic.ksu.edu.tw/linux_basic/0220filemanager.php 第七章.Linux 文件与目录管理 最近升级日期:2009/08/26 ...

  3. 第七章、Linux 文件与目录管理

    第七章.Linux 文件与目录管理   1. 目录与路径 1.1 相对路径与绝对路径 1.2 目录的相关操作: cd, pwd, mkdir, rmdir 1.3 关於运行档路径的变量: $PATH ...

  4. APUE(4)---文件和目录 (3)

    十三.函数rename和renameat #include <stdio.h> int rename(const char *oldname, const char *newname); ...

  5. 《UNIX环境高级编程》笔记——4.文件和目录

    一.引言 本章描述文件系统的其他特征和文件的性质.有些背景知识需要注意,例如用户ID与文件权限.文件系统等. 二.函数stat.fstat.fstatat和lstat #include <sys ...

  6. [APUE]文件和目录(中)

    一.link.unlink.remove和rename 一个文件可以有多个目录项指向其i节点.使用link函数可以创建一个指向现存文件连接 #include <unistd.h> int ...

  7. [APUE]文件和目录(上)

    一.文件权限 1. 各种ID 我在读这一章时遇到了各种ID,根据名字完全不清楚什么意思,幸好看到了这篇文章,http://blog.csdn.net/ccjjnn19890720/article/de ...

  8. ls: 无法访问/usr/sbin/smartctl: 没有那个文件或目录

    环境:RHEL6.5 + Oracle 11.2.0.4 RAC 在安装RAC时,检查时缺少包 cvuqdisk-1.0.9-1,oracle提供脚本修复安装. 但在执行时报错: [root@orad ...

  9. 【Linux命令】文件和目录操作命令

    本文主要用于常用命令的备忘,具体用法可用man查看,或查询其他资料. cd:改变工作目录 ls:列出目录的内容 mkdir:创建一个目录 cat:连接并显示指定的一个和多个文件的有关信息 cp:将给出 ...

随机推荐

  1. jmeter4.0测试dubbo接口遇到的问题:An error occurred: org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class

    半年前,用jmeter4.0测试dubbo接口的时候,遇到这样一个问题 An error occurred: org.springframework.scheduling.quartz.CronTri ...

  2. LOJ#6282. 数列分块入门 6

    一个动态的插入过程,还需要带有查询操作. 我可以把区间先分块,然后每个块块用vector来维护它的插入和查询操作,但是如果我现在这个块里的vector太大了,我可能的操作会变的太大,所以这时候我需要把 ...

  3. 【Linux】linux中文本操作利器grep,awk,sed

    grep命令 grep(global search regular expression)是一种强大的文本搜索工具,它可以使用正则表达式搜索文本,并把匹配的行打印出来.平时搜索文本中内容的时候是非常方 ...

  4. poj3259Wormholes (Bellman_Ford/SPFA/Floyed算法判断是否存在负环)

    题目链接:http://poj.org/problem?id=3259 题目大意:一个图,有n个顶点,其中有m条边是双向的且权值为为正,w条边是单向的且权值为负,判断途中是否存在负环,如果有输出YES ...

  5. kafka 流式计算

    http://www.infoq.com/cn/articles/kafka-analysis-part-7/ Kafka设计解析(七)- 流式计算的新贵 Kafka Stream

  6. 【转】服务化框架技术选型与京东JSF解密

    [京东技术]声明:本文转载自微信公众号“开涛的博客”,转载务必声明. 作者:章耿,原京东资深架构师,曾负责京东服务框架,配置中心等基础平台.近十年工作经验,专注于基础中间件等底层技术架构,对分布式系统 ...

  7. QML学习笔记(七)— 实现可拖拽、编辑、选中的ListView

    鼠标单击可选中当前项,头部呈绿色显示:按压当前项可进行拖拽更换列表项位置:点击数据可以进行编辑: GitHub:八至 作者:狐狸家的鱼 这里是自己定义的model,有些字体和颜色都是使用的全局属性, ...

  8. JMeter-Java压力测试工具-02

    这节介绍几个Listener下面的组件 Aggregate Report-汇总报告 从左到右依次:具有相同标签的样本数.一组结果的平均时间.一组结果的中间时间(50%的样本不超过这个时间).90%的样 ...

  9. 新建工程时报错(26, 13) Failed to resolve: com.android.support:appcompat-v7:28.+ ,

    allprojects { repositories { jcenter() maven { url "https://maven.google.com" } } }

  10. JSP学习记录

    <%@ page contentType="text/html;charset=gb2312" %> <html> <h1>计算器</h1 ...