第4章 文件和目录(5)_贯穿案例2:mini shell(1)

6. 贯穿案例2:mini shell(1)

【阶段任务】实现cd、pwd和quit命令

//job.h

#ifndef __JOB_H__
#define __JOB_H__

//接收命令行参数
typedef struct
{
    char** args;  //对应于主函数中的char* argv[]参数(含进程名本身)
}Program;

//命令行中可以包含多个程序(命令),如
//#date;ls -l,单个或多个命令通过cmd传入Job结构体中
typedef struct
{
    char* cmd; //单条命令或多条命令(用分号隔开)
    int progs_num;    //作业中包含程序的数量
    Program* progs;   //各个程序的命令行参数
}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);

#endif

//job.c

#include "job.h"
#include <malloc.h>
#include <assert.h>
#include <string.h>

//创建作业
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 = 0;
    job->progs = NULL;

    return job;
}

//销毁作业
void destroy_job(Job* job)
{
    assert(job != NULL);
    free(job->progs);
    free(job->cmd);
    free(job);
}

//arg格式:command  arg0 arg1 ==> 返回3
static int arg_num(char** arg)
{
    int ret = 0;
    char* start = arg[0];

    while(start != NULL){
        start = arg[++ret];
    }

    return ret;
}

//创建进程(命令)
Program* create_program(char** arg)
{
    Program* prog = (Program*)malloc(sizeof(Program));
    assert(prog != NULL);

    int counter = arg_num(arg);
    prog->args = (char**)calloc(counter + 1, sizeof(char*)); //以NULL结尾

    int i = 0;
    for(i=0; 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;  //指针数组,以NULL结尾

    return prog;
}

//销毁进程(命令)
void destroy_program(Program* prog)
{
    assert(prog != NULL);

    int i = 0;
    while(prog->args[i] != NULL)
    {
        free(prog->args[i++]);
    }

    free(prog->args);
    free(prog);
}

//将命令加入作业中
int add_program(Job* job, Program* prog)
{
    //重新申请一片空间以增加一条命令进来,放入job->progs中
    Program* ps = (Program*)malloc(sizeof(Program) * (job->progs_num + 1));
    memcpy(ps, job->progs, job->progs_num * sizeof(Program));

    ps[job->progs_num++] = *prog;//将新的进程(命令)加入进来

    free(job->progs); //释放旧的程序(命令)组
    job->progs = ps;

    return job->progs_num - 1; //返回新命令的索引号
}

//mshell.c

#include "job.h"
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>

char* prompt = "mshell> "; //命令行的提示符
#define MAX_COMMAND_LEN 256 //命令行最多的字符数

//cd命令
void cd_fun(Program* prog)
{
    if(chdir(prog->args[1]) < 0){
        perror("cd error");
    }
}

//pwd命令
void pwd_fun(Program* prog)
{
    char buffer[256];
    memset(buffer, 0, sizeof(buffer));

    if(getcwd(buffer, sizeof(buffer)) == NULL){
        perror("pwd error");
    }

    printf("%s\n", buffer);
}

//分析命令所带的参数(含进程名本身)
void split_cmd(Job* job, char* arguments)
{
    char** args = (char**)malloc(MAX_COMMAND_LEN * sizeof(char*));
    assert( args != NULL);

    char* cmd = strtok(arguments, " ");

    args[0] = (char*)malloc(strlen(cmd) * sizeof(char)); //命令本身
    strcpy(args[0], cmd);

    int i = 1;
    char* s = NULL;
    while((s = strtok(NULL, " ")) != NULL){  //将参数分隔出来
        args[i] = (char*)malloc(strlen(s) * sizeof(char));
        strcpy(args[i++], s);
    }

    //根据args创建一个Program
    Program* prog = create_program(args);
    add_program(job, prog);

    int j = 0;
    for(j=0; j < i; j++){
        free(args[j]);
    }

    free(args);
}

//多条命令的解析
void parse_cmd(Job* job, char* line)
{
    char buff [MAX_COMMAND_LEN];

    //以“;”号分隔多条命令
    char*  pos = line;
    char*  start = line;
    int count = 0;
    while( start < (line + strlen(line)) ){
        memset(buff, 0, sizeof(buff));
        if((pos = strchr(pos, ‘;‘)) == NULL)
        {
            pos = line + strlen(line);
        }

        count = pos-start;
        if(count > 0 ){
             memcpy(buff, start, count);
             split_cmd(job, buff);
        }
        start = ++pos;
    }
}

//执行命令
void execute_cmd(Job* job)
{
    int i = 0;
    for(i=0; i<job->progs_num; i++)
    {
        //cd命令
        if(!strcmp(job->progs[i].args[0], "cd")){
           cd_fun(&job->progs[i]);
        }

        //pwd命令
        if(!strcmp(job->progs[i].args[0], "pwd")){
           pwd_fun(&job->progs[i]);
        }

        //quit命令
        if(!strcmp(job->progs[i].args[0], "quit")){
           exit(0);
           return;
        }
    }
}

int main(int argc, char* argv[])
{
    char buffer[MAX_COMMAND_LEN];
    memset(buffer, 0, MAX_COMMAND_LEN);

    ssize_t size = strlen(prompt) * sizeof(char);
    write(STDOUT_FILENO, prompt, size);

    ssize_t len = 0;
    while(1){
        len = read(STDIN_FILENO, buffer, MAX_COMMAND_LEN);
        buffer[len -1] = 0;  //以NULL结尾

        if(strlen(buffer) > 0){
            Job* job = create_job(buffer);

            //解析命令
            parse_cmd(job, buffer);
            //执行命令
            execute_cmd(job);

            destroy_job(job);
        }

        write(STDOUT_FILENO, prompt, size);
        memset(buffer, 0, MAX_COMMAND_LEN);
    }

    return 0;
}
时间: 2024-12-18 17:09:01

第4章 文件和目录(5)_贯穿案例2:mini shell(1)的相关文章

APUE学习笔记:第四章 文件和目录

4.1 引言 本章将描述文件的特征和文件的性质 4.2 stat.fstat和lstat函数 #include<sys/stat.h> int stat(const char *restrict pathname,struct stat *restrict buf); int fstat(int filedes,struct stat *buf) int lstat(const char *restrict pathname,struct stat *restrict buf); 三个函数的返

第4章 文件和目录(3)_文件系统结构及软、硬链接

3. Linux文件系统结构 3.1 文件系统结构 (1)超级块 文件系统中的第一个块被称为超级块.这个块存放文件系统本身的信息.比如,记录了每个区域的大小,也存放了未被使用的磁盘块的信息.其包含的信息如下: 主要域 含义 Magic Number 用来检验是否是一个真正的EXT2文件系统超级块 Revision Level 主从修订版本号.让安装代码据此判断文件系统是否支持只存在于某个特定版本文件系统中的属性. Block Group Number 超级块的组数量 Block Size 以字节

APUE读书笔记-第四章 文件和目录

到第四章了,不知什么时候才能把这本书看完,耽误的时间太多了. 第四章是在第三章的基础上,主要描述文件系统的其他性质和文件的性质. 4.2 stat.fstat.fstatat.lstat函数 首先来看看这四个函数的原型: #include <sys/stat.h> ///usr/include/x86_64-linux-gnu/sys/ int stat (const char *__restrict __file, struct stat *__restrict __buf) int fst

第四章 文件和目录

本章主要介绍文件目录的创建.删除.读写.设置访问权限以及获取文件或目录的属性等: 唯一需要强调的可能就是:目录也是一种文件 获取文件目录的属性 关键函数 stat/fstat/lstat用于获取文件的信息,如文件的所有者,权限,修改和访问时间等等 #include <sys/stat.h> int fstat(int fildes, struct stat *buf); // 获取已打开的文件的相关信息 int fstat64(int fildes, struct stat64 *buf);

第二章 文件和目录操作命令

2.1 pwd (print work directory)打印工作目录(显示当前所在路径)  后面可以接 -L  默认情况下接的也是-L(logical)的 此种情况显示的是逻辑路径(相当于win的一样) -P(physical)的话,就会把真实的物理路径全部显示出来 [[email protected] local]# pwd /usr/local [[email protected] local]# cd - /root [[email protected] ~]# [[email pro

apue第四章 文件和目录

函数stat,fstat,fstatat, lstat #include <sys/stat.h> int stat(const char *restrict pathname, struct stat *restrict buf); int fstat(int fd, struct stat *buf); int lstat(const char *restrict pathname, struct stat *restrict buf); int lstat(int fd, const c

【Linux系列】【基础版】第二章 文件、目录管理

2. 文件.目录管理     2.1 有哪些文件目录         2.1.1 /bin          2.1.2 /boot         2.1.3 /dev         2.1.4 /etc         2.1.5 /home         2.1.6 /lib  /lib64         2.1.7 /meida         2.1.8 /mnt         2.1.9 /opt         2.1.10 /proc         2.1.11 /ru

《python编程》第四章——文件和目录工具

1.文件和目录,他们本身就是我们在电脑里看到的那些一个个文件.目录在windows中就是文件夹,很好理解. 2.我们用到的大多数用途,就是利用open内建函数及其文件对象来处理文件. 3.open函数返回的文件对象有多种方法,read,readline,readlines,write,writelines,close,seek,flush(将缓存区的数据强制转移到磁盘),fileno(获取底层的文件句柄)等. 4.打开一个文件的整个步骤都是分为三步的,1.打开,同时指定打开来做什么用(比如wri

apue 第4章 文件和目录

获取文件属性 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *pathname, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *pathname, struct stat *buf); #include <fcntl.h> #i

Linux命令应用大词典-第 15章 文件、目录权限和属性

15.1 chmod:更改文件和目录的模式 15.2 chown:更改文件和目录的用户所有者和组群所有者 15.3 chgrp:更改文件或目录的所属组 15.4 umask:显示和设置文件及目录创建默认权限掩码 15.5 getfacl:显示文件或目录的ACL 15.6 setfacl:设置文件或目录的ACL 15.7 chacl:更改文件或目录的acl 15.8 lsattr:查看文件和目录的属性 15.9 chattr:更改文件和目录的属性 15.1 chmod:更改文件和目录的模式 15.