主函数运行要去读取从标准输入或终端上输入的整个命令行,然后再去解析命令行参数,解析出来之后,要将其封装成一个 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. luogu5021 [NOIp2018]赛道修建 (二分答案+dp(贪心?))

    首先二分一下答案,就变成了找长度>=m的 不相交的路径的个数 考虑到在一个子树中,只有一个点能出这个子树去和别的点搞 所以我这个子树里尽量自我满足是不会有坏处的 而且要在自我满足数最大的条件下, ...

  2. bzoj4481非诚勿扰(期望dp)

    有n个女性和n个男性.每个女性的如意郎君列表都是所有男性的一个子集,并且可能为空.如果列表非空,她们会在其中选择一个男性作为自己最终接受的对象.将“如意郎君列表”中的男性按照编号从小到大的顺序呈现给她 ...

  3. zookeeper部署

    版本:zookeeper-3.4.5-cdh5.10.0.tar.gz 网址:http://archive-primary.cloudera.com/cdh5/cdh/5/ 1. 解压 $ tar - ...

  4. javascript的性能优化tips

    谈到javascript的性能优化,有好多点,比如把script放到离body闭合标签附近,合并多个script标签等等,还有一些代码的性能,for的性能不如while的性能好,用while模拟for ...

  5. luogu3731 新型城市化

    题目链接 思路 这道题对于题意的转化很关键. 题目要求的是添上一条边,使得图中最大团的大小变大.给出的边是原图的补集,这就给我们了提示. 因为题目中说,原图中最多有两个团.所以给出的边一定形成了一个二 ...

  6. SecureCRT或XShell软件

    SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录UNIX或Linux服务器主机的软件. Xshell 是一个强大的安全终端模拟软件,它支持SSH1 ...

  7. 第一篇-Win10打开txt文件出现中文乱码

    如果刚开始安装的是英文的Win10系统,那么打开txt文件时很容易出现乱码问题.包括打开cmd窗口,也是不能显示中文的.当然,麻烦的处理方法是: 在cmd中想要显示中文:先输入chcp 936,之后中 ...

  8. 【译】9. Java反射——泛型

    原文地址:http://tutorials.jenkov.com/java-reflection/generics.html ===================================== ...

  9. 数位DP入门题

    站点一览: hdu 2089"不要62" hdu 4734"F(X)" poj 3252"Round Numbers" hdu 3709&q ...

  10. java和c#中的装箱和拆箱操作

    c#装箱和拆箱 装箱:整体上来说,装箱是将值类型转换成引用类型,比如将Vector3转换成Object类型. 具体而言: 1)在托管堆中为值类型分配内存.除了原始的数值以外还应该有指向该数值的引用. ...