C语言实现简单的minishell

探索开源项目:MiniShell

引言

在计算机编程的世界里,Shell 是一个至关重要的组成部分,它允许用户与操作系统交互,执行命令和程序。MiniShell 是一个简化版的 Shell 程序,通常用于教学和学习目的。在本文中,我们将深入分析一个 MiniShell 的实现代码,并探讨其功能和潜在的应用场景。

简单的命令解释器minishell 

Minishell项目的功能,主要就是实现命令的运行。

涉及命令如下:

1,cp  复制文件 cp 1 2 把文件1复制成文件2

2,cat 查看文件 cat 1  查看文件到内容

3,cd  切换路径 cd 1   切换到目录1中      //chdir 

4,ls  查看当前目录下到文件 ls 或 ls /home   

5,ll  查看当前目录下到文件 ll 或 ll /home    ls -l  

6,touch 新建文件  touch 1  新建文件 1  

7,rm删除文件 

Minishell的业务流程:

  1. 运行程序 ,打印提示符

linux@ubuntu:~$    

用户名@主机名:当前路径$ 

  1. 输入 要操作的命令 

  2. 程序负责执行相关的命令 

  3. Exit 程序的退出

程序的实现流程:

  1. 运行程序 ,打印提示符     ---- 提示符打印

linux@ubuntu:~$    

用户名@主机名:当前路径$ //getcwd -- sprintf();  //promt

  1. 输入 要操作的命令        ------ 解析命令 

cd .. 

ls 

touch 1.txt 

cat file 

cp src.txt dest.txt 

命令的格式:

<命令> [选项] [参数]

  1. 程序负责执行相关的命令 ---- 执行命令的功能 

  2. Exit 程序的退出 

[开 始]

     |

[打印提示符]

     |

[等待用户输入] //fgets

     |

[解析输入的命令]

     |

[根据命令执行对应的操作]

|

[结束]

所有命令按照其指定格式运行。

利用Linux中IO接收实现MiniShell

Minishell框图:

Minishell流程图:

代码分析

包含的头文件

MiniShell 程序首先包含了多个头文件,这些头文件提供了对文件描述符、目录遍历、系统调用等功能的支持。

 

#include <stdio.h> #include <fcntl.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <pwd.h> #include <cstdlib> #include <ctime> #include <errno.h> #include <cstring> #include <limits.h>

辅助函数

程序定义了一个 location 函数,该函数根据给定的时间戳返回一个 tm 结构体指针,用于时间的本地化处理。

 

struct tm* location(const time_t *timer);

文件和目录列表显示

lsl 函数用于以 ls -l 的格式显示文件和目录的详细信息,包括类型、权限、链接数、所有者、组、大小、最后修改时间和文件名。

 

void lsl(const char *name) { // ... 省略部分代码 ... }

计算磁盘使用情况

total 函数计算当前目录下的总磁盘使用量,包括文件所占用的块数。

 

int total() { // ... 省略部分代码 ... }

全部文件和目录的显示

lslall 函数结合了 totallsl 函数,显示当前目录下所有文件和目录的详细信息,并显示总磁盘使用量。

 

void lslall() { // ... 省略部分代码 ... }

显示所有文件和目录(包括隐藏文件)

ls_a 函数显示当前目录下的所有文件和目录,包括以点(.)开头的隐藏文件。

 

void ls_a() { // ... 省略部分代码 ... }

搜索特定文件或目录

ls_f 函数搜索当前目录下与指定名称匹配的文件或目录,并显示其详细信息。

 

void ls_f(const char *filename) { // ... 省略部分代码 ... }

内容查看

cat 函数实现了内容查看功能,它打开指定的文件,并将其内容输出到标准输出。

 

int cat(const char* filename) { // ... 省略部分代码 ... }

当前目录显示

printdir 函数用于显示当前的工作目录,并在末尾添加 $ 提示符。

 

void printdir() { // ... 省略部分代码 ... }

目录切换

change_directory 函数接受一个目录名参数,并尝试切换到该目录。

 

void change_directory(const char *dir_name) { // ... 省略部分代码 ... }

文件复制

do_cp_filedo_cp_dir 函数分别用于复制文件和目录。它们处理文件的打开、读取、写入和关闭。

 

int do_cp_file(const char *src, const char *dest) { // ... 省略部分代码 ... } int do_cp_dir(const char *dir_s, const char *dir_d) { // ... 省略部分代码 ... }

创建空文件

touch 函数用于创建一个空文件,如果文件已存在,则不进行任何操作。

 

void touch(const char* filename) { // ... 省略部分代码 ... }

删除文件

delete_file 函数尝试删除指定的文件,并在失败时打印错误信息。

 

int delete_file(const char *filename) { // ... 省略部分代码 ... }

命令判断

judge 函数是 MiniShell 的核心,它读取用户输入的命令,并根据命令类型调用相应的函数。

 

int judge() { // ... 省略部分代码 ... }

主函数

调用命令判断函数并且打印相应内容

以下是我

#include <stdio.h>
#include<fcntl.h>
#include<dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include<stdlib.h>
#include<time.h>
#include<errno.h>
#include<string.h>
#include <limits.h>

struct tm*location(const time_t *timer);

void lsl(const char *name)
{
    struct stat st;
if (stat(name,&st) < 0)
    {
        perror("stat fail");
    }
    switch (st.st_mode&S_IFMT)
    {
    case S_IFSOCK:
        putchar('s');
        break;
    case S_IFLNK:
        putchar('l');
        break;

    case S_IFREG:  
        putchar('-');
        break;
    case S_IFBLK:  
        putchar('b');
        break;
    case S_IFDIR:  
        putchar('d');
        break;
    case S_IFCHR:  
        putchar('c');
        break;
    case S_IFIFO:  
        putchar('p');
        break;
    }

    st.st_mode&S_IRUSR?putchar('r'):putchar('-'); 
    st.st_mode&S_IWUSR?putchar('w'):putchar('-'); 
    st.st_mode&S_IXUSR?putchar('x'):putchar('-'); 
    
    st.st_mode&S_IRGRP?putchar('r'):putchar('-'); 
    st.st_mode&S_IWGRP?putchar('w'):putchar('-'); 
    st.st_mode&S_IXGRP?putchar('x'):putchar('-');

    st.st_mode&S_IROTH?putchar('r'):putchar('-'); 
    st.st_mode&S_IWOTH?putchar('w'):putchar('-'); 
    st.st_mode&S_IXOTH?putchar('x'):putchar('-');

    printf(" ");
    printf("%ld ",st.st_nlink);

    printf("%s ",getpwuid(st.st_uid)->pw_name);
    printf("%s ",getpwuid(st.st_gid)->pw_name);
    printf("%ld\t",st.st_size);

    struct tm* t = localtime(&st.st_mtime);
    printf("%2d月  %2d %02d:%02d ", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min);
    printf(" %s\n",name);
}

int total()
{
    int t=0;
    char buf[100];
    getcwd(buf,sizeof(buf));
    DIR *dir = opendir(buf);
    struct dirent *pdir = NULL;
    while (pdir = readdir(dir))
    {
        struct stat st;
        if (stat(buf,&st) < 0)
        {
            perror("stat fail");
        }
    t=t+st.st_blocks/2;
    }
    return t+4;
}

void lslall()
{
    char buf[100];
    getcwd(buf,sizeof(buf));
    DIR *dir = opendir(buf);
    struct dirent *pdir = NULL;
    printf("total %d\n",total());
    while (pdir = readdir(dir))
    {
        if(pdir->d_name[0]!='.')
        lsl(pdir->d_name);
    }
}

void ls_a()
{
    char buf[100];
    getcwd(buf,sizeof(buf));
    DIR *dir = opendir(buf);
    struct dirent *pdir = NULL;
    while (pdir = readdir(dir))
    {
        printf("%s  ",pdir->d_name);
    }
    printf("\n");
}

void ls_()
{
    char buf[100];
    getcwd(buf,sizeof(buf));
    DIR *dir = opendir(buf);
    struct dirent *pdir = NULL;
    while (pdir = readdir(dir))
    {
        if(pdir->d_name[0]!='.')
        printf("%s  ",pdir->d_name);
    }
    printf("\n");
}

void ls_f(const char *filename)
{
    char buf[1000];
    getcwd(buf,sizeof(buf));
    DIR *dir = opendir(buf);
    struct dirent *pdir = NULL;
    while (pdir = readdir(dir))
    {
        if(strcmp(pdir->d_name,filename)==0&&pdir->d_type!=DT_DIR)
        {
            printf("%s  ",pdir->d_name);
            printf("\n");
        }
        if((strcmp(pdir->d_name,filename)==0)&&pdir->d_type==DT_DIR)
        {
            char buff[100];
            getcwd(buff,sizeof(buff));
            chdir(filename);
            ls_();
            chdir(buff);
            break;
        }
    }
}

int cat(const char* filename) {
    FILE *fp;
    char buf[1000];
    ssize_t bytes_read;
    fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("fopen");
        return -1;
    }
    while ((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0) {
        if (write(STDOUT_FILENO, buf, bytes_read) < 0) {
            perror("write");
            fclose(fp);
            return -1;
        }
    }
    if (bytes_read < 0) {
        perror("fread");
        fclose(fp);
        return -1;
    }
    fclose(fp);
    return 0;
}

void printdir()
{
    char buf[1000];
    fflush(stdout);
    getcwd(buf,sizeof(buf));
    //printf("%s$ ",buf);
    int ret=strlen(buf);
    buf[ret]='$';
    buf[ret+1]=' ';
    write(stdout->_fileno,buf,ret+2);
}

void change_directory(const char *dir_name) {
    // 获取当前工作目录
    char current_path[PATH_MAX];
    if (getcwd(current_path, sizeof(current_path)) == NULL) {
        perror("getcwd");
    }
    // 构建新的目录路径
    char new_path[PATH_MAX];
    if (dir_name[0] == '/') {
        // 如果传入的目录名是绝对路径,直接使用它
        snprintf(new_path, sizeof(new_path), "%s", dir_name);
    } else {
        // 如果传入的目录名是相对路径,将其与当前路径组合
        snprintf(new_path, sizeof(new_path), "%s/%s", current_path, dir_name);
    }

    // 切换到新的目录
    if (chdir(new_path) != 0) {
        perror("chdir");
    }
}

int do_cp_file(const char *src,const char *dest)
{
    int fd_s = open(src,O_RDONLY);
    int fd_d = open(dest,O_WRONLY|O_CREAT|O_TRUNC,0666);

    if (fd_s < 0 || fd_d < 0)
    {
        perror("open fail");
        return -1;
    }

    int ret = 0;
    char buf[100] = {0};

    while (ret = read(fd_s,buf,sizeof(buf)))
    {
        write(fd_d,buf,ret);
    }

    close(fd_s);
    close(fd_d);

    return 0;

}

void touch(const char* filename) 
{
    int fd=open(filename,O_RDWR|O_CREAT,0777);
    if(fd<0)
    {
        perror("open fail");
    }
}

int do_cp_dir(const char *dir_s,const char *dir_d)
{
    if (mkdir(dir_d,0777) < 0 && errno!=EEXIST)
    {
        perror("mkdir fail");
        return -1;
    }

    DIR *dir = opendir(dir_s);
    if (dir == NULL)
    {
        perror("opendir fail");
        return -1;
    }

    while (1)
    {
        struct dirent *pdir = readdir(dir);

        char spath[512];
        char dpath[512];

        if (pdir == NULL)
            break;
        //dir_s 
        //dir_s/
        if (pdir->d_name[0] != '.')
        {
            dir_s[strlen(dir_s)-1]=='/'?sprintf(spath,"%s%s",dir_s,pdir->d_name):sprintf(spath,"%s/%s",dir_s,pdir->d_name); //"dir_s/1.txt" 
            dir_d[strlen(dir_d)-1]=='/'?sprintf(dpath,"%s%s",dir_d,pdir->d_name):sprintf(dpath,"%s/%s",dir_d,pdir->d_name); //"dir_s/1.txt" 
            if (pdir->d_type == DT_DIR)
            {
                do_cp_dir(spath,dpath);
            }else 
            {
                do_cp_file(spath,dpath);

            }
        }
    }

    closedir(dir);
    return 0;
}

int delete_file(const char *filename) {
    if (remove(filename) != 0) {
        perror("remove");
        return -1; // 删除失败
    }
    return 0; // 删除成功
}

int judge()
{
    char buf[100];
    fflush(stdin);
    int ret = read(stdin->_fileno,buf,sizeof(buf));
    buf[ret-1]='\0';
    if(strcmp(buf,"ls -l")==0)
        lslall();
    if(strncmp(buf,"ls ",3)==0&&buf[3]!='-'&&buf[4]!='l')
    {
        char buff[100];
        char temp[100];
        if(buf[3]!='/')
        {
        char *arg = buf + 3;// 跳过 "ls -l " 前缀
        ls_f(arg);
        }
        else
        {
            printf("here");
            char *arg = buf + 3;
            getcwd(buff,sizeof(buff));
            change_directory(arg);
            getcwd(temp,sizeof(temp));
            ls_();
            change_directory(buff);
        }
    }
    
    if(strcmp(buf,"ls")==0)
        ls_();
    if(strcmp(buf,"ls -a")==0)
        ls_a();
    if(strncmp(buf,"ls -l ",6)==0)
    {
        char buff[100];
        char temp[100];
        char bufff[1000];
        getcwd(bufff,sizeof(bufff));
        DIR *dir = opendir(bufff);
        struct dirent *pdir = NULL;
        char *arg = buf + 6;
        int t=0;
        while(pdir=readdir(dir))
        {
        if(strcmp(pdir->d_name,arg)==0&&pdir->d_type!=DT_DIR)
        t=1;
        }
        if(t)
        {
            lsl(arg);
        }
        else
        {
            getcwd(buff,sizeof(buff));
            change_directory(arg);
            getcwd(temp,sizeof(temp));
            lslall(temp);
            change_directory(buff);
        }
    }
    if(strncmp(buf,"cat ",4)==0)
    {
        char *arg = buf + 4; // 跳过 "ls -l " 前缀
        cat(arg);
    }

    if(strncmp(buf,"cd ",3)==0)
    {
        char *arg = buf + 3; // 跳过 "ls -l " 前缀
        change_directory(arg);
    }
    if(strncmp(buf,"cp ",3)==0)
    {
        char *arg = buf + 3; // 跳过 "ls -l " 前缀
        char *source = strtok(arg, " "); // 使用空格分割字符串,获取源文件名
        char *destination = strtok(NULL, " "); // 继续分割,获取目标路径
        do_cp_dir(source,destination);
    }
    if(strncmp(buf,"rm ",3)==0)
    {
        char *arg = buf + 3; // 跳过 "ls -l " 前缀
        delete_file(arg);
    }
    if(strncmp(buf,"touch ",6)==0)
    {
        char *arg = buf + 6; // 跳过 "ls -l " 前缀
        touch(arg);
    }
    if(strncmp(buf,"exit",4)==0)
    {
        char *arg = buf + 4; // 跳过 "ls -l " 前缀
        return -1;
    }
    return 0;
}

int main(int argc, const char *argv[])
{
    while(1)
    {
        printdir();
        if(judge()==-1)
        break;
    }

    return 0;
}

MiniShell 是一个用 C 语言实现的轻量级 Shell 程序,它模拟了 UNIX Shell 的一些基本功能,如文件列表显示、内容查看、目录切换、文件复制、文件删除和创建空文件等。通过分析 MiniShell 的代码,我们可以深入了解 Shell 程序的工作原理,以及操作系统中文件和目录操作的底层实现。

MiniShell 的设计简洁,易于理解,适合作为学习材料,帮助初学者掌握系统编程和 Shell 脚本编写的基础知识。同时,MiniShell 也可以作为开发更高级 Shell 程序的基础框架,通过扩展和定制,实现更多复杂的功能。

总的来说,MiniShell 虽然功能有限,但它提供了一个很好的起点,让我们能够探索和学习 Shell 编程的核心概念。随着技术的不断进步和创新,我们可以期待 MiniShell 以及类似的工具在未来发挥更大的作用,帮助更多的人掌握计算机编程的精髓。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/39142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《梦醒蝶飞:释放Excel函数与公式的力量》8.2 COUNTA函数

8.2 COUNTA函数 COUNTA函数是Excel中用于统计指定区域内所有非空单元格数量的函数。它能够统计数值、文本、错误值以及公式返回的结果&#xff0c;是数据分析中常用的统计工具。 8.2.1 函数简介 COUNTA函数用于统计指定区域中所有非空单元格的数量。它与COUNT函数不同&#…

创新校园服务模式 跑腿小程序平台源码构建与实践 前后端分离 带完整的安装代码包以及部署教程

系统概述 本项目是一个集任务发布、接单、支付、评价于一体的跑腿服务小程序平台&#xff0c;专为高校校园设计。系统采用前后端分离架构&#xff0c;前端负责用户界面展示和交互逻辑&#xff0c;后端处理业务逻辑、数据存取等&#xff0c;两者通过API接口进行通信&#xff0c…

二叉树的右视图-二叉树

199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 层序遍历&#xff0c;广度优先 queue先进后出&#xff0c;每层从左往右进树&#xff0c;最后一个就是最右边的数&#xff1b;pop掉这层的。push下一层&#xff1b; class Solution { public:vector<int> r…

楼层分户项目分析

文章目录 1. 区域绘制2. 户型切分3. 楼房分层4. 编辑房户信息5. 查看房户信息6. 数据库6.1. 楼栋数据库6.2. 单位数据库 7. 房户数据库 1. 区域绘制 点击绘制图形&#xff0c;激活画笔&#xff0c;右键结束绘制。 输入框可以更换地址前缀。 分户坐标是由绘制的多个点组成的&…

深度学习笔记: 最详尽解释混淆矩阵 Confusion Matrix

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 混淆矩阵 假设我们有包含临床测量数据的医疗数据&#xff0c;例如胸痛、良好的血液循环、动脉阻塞和体重…

如何将音频文件发送至摄像头

目前再很多互联互通的场景下&#xff0c;如AI盒子再从摄像头上取视频分析&#xff0c;分析出发生某个事件&#xff0c;需要反向通过摄像头的喇叭播放语音&#xff0c;发出告警提示&#xff0c;使用场景如下 盒子上对于此类场景的需求往往不能满足&#xff0c;或者为这个需求需要…

APP性能测试

1、性能测试分类&#xff1a;&#xff08;CPU&#xff0c;内存&#xff0c;流量&#xff0c;时间&#xff08;启动耗时计算&#xff09;&#xff0c;电量&#xff0c;流畅度&#xff08;帧率&#xff09;&#xff09;&#xff0c;稳定性&#xff08;崩溃&#xff0c;闪退&#…

感动的短视频:成都柏煜文化传媒有限公司

感动的短视频&#xff1a;瞬间触动心灵的温暖力量 在这个快节奏、高压力的时代&#xff0c;我们常常在忙碌与喧嚣中穿梭&#xff0c;心灵深处那份最纯粹的感动似乎变得愈发珍贵而难得。然而&#xff0c;就在这样一个数字化盛行的今天&#xff0c;短视频以其独特的魅力&#xf…

二百四十二、Hive——Hive的动态分区表出现day=__HIVE_DEFAULT_PARTITION__分区

一、目的 Hive的DWD层动态分区表的分区出现day__HIVE_DEFAULT_PARTITION__&#xff0c;有点懵&#xff0c;而且表中数据的day字段也显示__HIVE_DEFAULT_PARTITION__ 1、DWD层动态分区表的分区 __HIVE_DEFAULT_PARTITION__ 2、DWD层分区字段day数据 __HIVE_DEFAULT_PARTITION…

农业气象监测仪:现代农业的“守护神”

随着科技的不断进步&#xff0c;农业生产也逐渐迈入了智能化的新时代。在众多的农业科技产品中&#xff0c;农业气象监测仪以其独特的优势&#xff0c;成为了现代农业不可或缺的一部分。本文将从多个角度探讨农业气象监测仪在农业中的优势&#xff0c;以及它如何助力农业生产实…

事务的概念-事务的概念、事务的定义(BEGIN TRANSACTION、COMMIT、ROLLBACK)

数据库系统中的事务&#xff0c;是保证系统在发生故障后或存在并发操作的情况下&#xff0c;数据库中的数据与企业业务结果相一致 一、事务的概念 在许多数据库应用系统中&#xff0c;数据库用来存储现实世界中一些企业的状态信息或其管理的数据 1、概念一 &#xff08;1&a…

pdf合并工具,pdf合并器,多个pdf合并成一个pdf

你是否有过这样的困扰&#xff1a;手头上有好几个pdfF文档&#xff0c;需要将它们合并成一个单一的文件&#xff0c;但却不知道从何下手&#xff1f;别担心&#xff0c;这篇文章将为你揭秘多个pdf合并成一个pdf的方法&#xff0c;让你轻松实现pdf文档整合的问题&#xff01; 首…

python 中的 下划线_ 是啥意思

在 Python 中&#xff0c;_&#xff08;下划线&#xff09;通常用作占位符&#xff0c;表示一个变量名&#xff0c;但程序中不会实际使用这个变量的值。 目录 忽略循环变量&#xff1a;忽略函数返回值&#xff1a;在解释器中使用&#xff1a;举例子1. 忽略循环变量2. 忽略不需…

11集在Docker上编译tensorFlow Lite MCU例子工程-《MCU嵌入式AI开发笔记》

【11集在Docker上编译tensorFlow Lite MCU例子工程-《MCU嵌入式AI开发笔记》】 这一集咱们一步一步的在doc下面编译TensorFlow Lite的例程 https://tensorflow.google.cn/lite/tutorials?hlzh-cn 进入这个例子&#xff1a; https://codelabs.developers.google.cn/codelabs/…

C# Web控件与数据感应之属性统一设置

目录 关于属性统一设置 准备数据源 范例运行环境 AttributeInducingFieldName 方法 设计与实现 如何根据 ID 查找控件 FindControlEx 方法 调用示例 小结 关于属性统一设置 数据感应也即数据捆绑&#xff0c;是一种动态的&#xff0c;Web控件与数据源之间的交互&…

高编:线程(2)——同步与互斥

一、互斥 概念&#xff1a; 互斥 》在多线程中对 临界资源 的 排他性访问。 互斥机制 》互斥锁 》保证临界资源的访问控制。 pthread_mutex_t mutex; 互斥锁类型 互斥锁变量 内核对象 框架&#xff1a; 定义互斥锁 》初始化锁 》加锁 》解锁 》销…

STL的六大组件

一.总体概念 STL&#xff08;Standard Template Library&#xff0c;标准模板库&#xff09;是C标准库的一部分&#xff0c;提供了丰富且高效的数据结构和算法。STL主要由六大组件组成&#xff0c;它们是&#xff1a; 容器&#xff08;Containers&#xff09;&#xff1a;STL提…

1.(vue3.x+vite)实现卷帘效果

前端技术社区总目录(订阅之前请先查看该博客) 1:效果预览 2:代码编写 <template><div style="width

如何使用Maxscript访问C#类库?

本教程帮助你一步一步集成maxscript文档和C#类库&#xff0c;以便你能够在maxscript提供的相当有限的环境中访问dotnet框架的强大功能。这让你可以使用maxscript做一些功能更强大的事情&#xff0c;比如访问数据库、获取web部署的内容等等。 还是直接上教程实惠&#xff1a; …

昇思25天学习打卡营第6天|关于函数与神经网络梯度相关技术探讨

目录 Python 库及 MindSpore 相关模块和类的导入 函数与计算图 微分函数与梯度计算 Stop Gradient Auxiliary data 神经网络梯度计算 Python 库及 MindSpore 相关模块和类的导入 Python 中的 numpy 库被成功导入&#xff0c;并简称为 np。numpy 在科学计算领域应用广泛&#x…