主函数运行要去读取从标准输入或终端上输入的整个命令行,然后再去解析命令行参数,解析出来之后,要将其封装成一个 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. Nginx+Tomcat-cluster构建

    -----------ReProxy-------------------------Client-----------192.168.56.202 nginx 192.168.56.200 Tomc ...

  2. selenium 代理设置

    设置Firefox代理: from selenium import webdriver from selenium.webdriver.common.proxy import Proxy, Proxy ...

  3. layui记录

    layui 官网 layui 独立版 layui mobile layui 社区

  4. kafka 流式计算

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

  5. c#委托中的匿名方法和lambda表达式

    一.一般委托方式 Func<int, int, int> AddMethodHander; public unName() { AddMethodHander += AddMethod; ...

  6. 冒泡排序Java版

    package dataStructureAlgorithmReview.day01; import java.util.Arrays; /** * 冒泡 * @author shundong * * ...

  7. 信用评分卡 (part 7 of 7)

    python信用评分卡(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_camp ...

  8. maven_问题

    问题:was cached in the local repository, resolution will not be reattempted until the update interval ...

  9. docker 基础之镜像加速

    国内访问 Docker Hub 有时会遇到困难,此时可以配置镜像加速器 对于使用 systemd 的系统,用 systemctl enable docker 启用服务后,编辑 /etc/systemd ...

  10. Linux虚拟内存(swap)调优篇-“swappiness”,“vm.dirty_background_ratio”和“vm.dirty_ratio”

      Linux虚拟内存(swap)调优篇-“swappiness”,“vm.dirty_background_ratio”和“vm.dirty_ratio” 作者:尹正杰 版权声明:原创作品,谢绝转载 ...