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

    快捷键: 先定义name,age再利用快捷键生成,Alt+shift+s +c:空参 Alt+shift+s +o:有参 Alt+shift+s +r:set&get方法Ctrl+shift+ ...

  2. 利用mysqldump命令导出为csv格式文件

    解决方法: 先导出为txt文件,其内容是以逗号“,”分隔的,得到txt文件后,再自行处理为.csv或者.xls文件. 参数说明: -t, --no-create-info   Don't write ...

  3. LOJ#2720 你的名字

    题意:给定母串s和若干个询问.每个询问是一个串t和两个数l,r,表示求t中有多少个本质不同的子串没有在s[l,r]中出现过. 解:我写的并不是正解......是个毒瘤做法.只在loj上面卡时过了就写l ...

  4. 【POJ2230】Watchcow

    题目大意:给定一个 N 个点,M 条边的无向图,要求不重复地经过每条边两次,并且从 1 号节点出发最后回到 1 号节点,求一条路径. 题解:不重复地经过两次这个操作很容易地通过无向图的建边方式来实现, ...

  5. 第二十九篇-Fragment动态用法

    效果图: 上节学习了静态添加Fragment的方法,这节学习动态添加方法. 主页面 layout.xml Fragment页面 layout2.xml 实现功能,当点击主页面的button时,将Fra ...

  6. PHP的简单工厂模式

    又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式.在简单工厂模式中,可以根据参数的不同返回不同类的实例.简单工厂模式专门定义一个类来负责创建其他类的实例,被创建 ...

  7. 某些浏览器具有dns缓存功能,大家更改域名指向,建议清理下浏览器缓存

    最近遇到一个很郁闷的问题,在我们的的ngnix服务器上原来默认的网址需要更改.更改后,重启了ngnix.可是在客户端使用360浏览器打开网址.地址还是指向旧地址.直接输入服务器 IP地址转向了新地址, ...

  8. NTT学习笔记

    和\(FFT\)相对应的,把单位根换成了原根,把共轭复数换成了原根的逆元,最后输出的时候记得乘以原\(N\)的逆元即可. #include <bits/stdc++.h> using na ...

  9. 安装Redis 4.0单实例

    一.Redis简单介绍 转载于网络 Redis是一个开源(BSD许可)的内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件.由于Redis采用运行在内存中的数据集工作方式,其性能卓越,能支持 ...

  10. Linux下进程与线程的区别及查询方法

    在平时工作中,经常会听到应用程序的进程和线程的概念,那么它们两个之间究竟有什么关系或不同呢?一.深入理解进程和线程的区别 1)两者概念 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进 ...