操作系统实验: Mini Shell(完整源代码)

OS Lab: Mini Shell

题目: 在 Linux 平台上,采用 C 语言编写一个 Mini Shell 命令解释环境(即类似 Bash Shell 环境)。该环境可以循环接受用户(从标准输入中)输入的(外部和内部)命令以及若干参数,然后能对上述命令进行解析和执行,最后将用户输入的命令的执行结果显示在标准输出上。即:

bash-2.03$ ps_03

**************welcome to mini shell**************

MINI SHELL#pwd /home/unixmng/oscourses/ps_prog

MINI SHELL#exit ****************** mini shell exit******************

bash-2.03$

要求:

  • 支持用户输入一行命令及其多个参数,并解析执行,并输出结果;
  • 支持 cd 命令,若无参数则回到当前用户的登录目录(见下面提示);
  • 支持以“当前路径”和“用户名”为提示符;
  • 支持对命令行中空格的自动忽略处理;
  • 支持对命令行中 tab 键的自动忽略处理;
  • 支持一行中以“;”(为标志)分隔的多个命令及多个参数的顺序执行,即如下:

MINI SHELL#pwd; ls –l;date

说明:上述三个命令须在本 Mini Shell 下依次顺序执行,最后由 Mini Shell 再次循环接受用户的新命令。

提交成果:

  • Mini Shell 源程序
  • 功能测试实例文件

相关头文件:

#include <stdio.h> #include <string.h> #include <unistd.h> #include <pwd.h>

相关参考函数:

  • forkexecvpwait:创建进程
  • strcmpstrcpystrncpy :字符串相关操作
  • fopenfclosefscanffprintffgetsfputs:文件 stdio 操作
  • sprintf :任意类型转换为字符串
  • atoi :字符串转换为整数类型 int
  • getlogin :获取当前用户名
  • getcwd :获取当前路径
  • chdir :改变当前路径
  • getenv :获取环境变量
  • 获取当前用户的登录目录

完整源代码:

#include <dirent.h>
#include <libgen.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdlib>
#include <sstream>
#include <pwd.h>
#include <fcntl.h>

using namespace std;

#define SUCCESS 0
#define ERROR -1

int reflag = 0;
char current_dir[100];
char user_dir[100];
vector<string> re;

int eval(vector<string> res);

vector<string> split(const string &s, const string &separator);

int eval(vector<string> res) {
    if (res[0] == "cd") {
        if (res.size() == 1) {
            strcpy(current_dir, user_dir);
        } else {
            const char *rest = res[1].c_str();
            if (res[1] == "/") {
                opendir(rest);
                strcpy(current_dir, rest);
            } else if (res[1] == "..") {
                char *parent_dir = dirname(current_dir);
                strcpy(current_dir, parent_dir);
            } else if (res[1] == "~") {
                strcpy(current_dir, user_dir);
            } else {
                char target_path[100];
                cout << "current dir: " << current_dir << endl;
                if (strcmp(current_dir, "/") == 0) {
                    snprintf(target_path, 1024, "%s%s", current_dir, rest);
                } else {
                    snprintf(target_path, 1024, "%s/%s", current_dir, rest);
                }
                if (opendir(target_path) == NULL) {
                    cout << "cd: " << rest << ":";
                    printf("\033[31m  没有那个文件或目录.\n\033[0m");
                    return ERROR;
                }
                strcpy(current_dir, target_path);
            }
            cout << current_dir << endl;
            return ERROR;
        }
    } else if (res[0] == "pwd") {
        char buf[300];
        cout << current_dir << endl;
    } else if (res[0] == "ls") {
        int pid = fork(), wpid;
        int status;
        int count = 0;
        const char *rest = res[0].c_str();

        if (pid == 0) {
            char *env[] = {0, NULL};
            for (int i = 0; i < res.size(); i++) {
                if (res[i] == ">") {
                    reflag = 1;
                    count = i;
                }
                if (res[i] == ">>") {
                    reflag = 2;
                    count = i;
                }
            }
            if (reflag != 0) {
                char **cmd_temp = new char *[count];

                for (int i = 0; i < count; i++) {
                    cmd_temp[i] = new char[500];
                    memset(cmd_temp[i], 0, sizeof(cmd_temp[i]));
                }
                for (int i = 0; i < count; i++) {
                    strcpy(cmd_temp[i], res[i].c_str());
                }
                cmd_temp[count] = current_dir;
                cmd_temp[count + 1] = NULL;

                int fd = 1;
                if (reflag == 1)
                    fd = open(res[count + 1].c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0664);
                else if (reflag == 2)
                    fd = open(res[count + 1].c_str(), O_CREAT | O_WRONLY | O_APPEND, 0664);
                dup2(fd, 1);
                if (execvp(rest, cmd_temp) < 0) {
                    printf("\033[31m%s:command not found.\n\033[0m", res[0].c_str());
                }
            } else {
                char **cmd_temp = new char *[res.size() + 1];
                for (int i = 0; i < res.size(); i++) {
                    cmd_temp[i] = new char[500];
                    memset(cmd_temp[i], 0, sizeof(cmd_temp[i]));
                }
                for (int i = 0; i < res.size(); i++) {
                    strcpy(cmd_temp[i], res[i].c_str());
                }
                cmd_temp[res.size()] = current_dir;
                cmd_temp[res.size() + 1] = NULL;
                if (execvp(rest, cmd_temp) < 0) {
                    printf("\033[31m%s:command not found.\n\033[0m", res[0].c_str());
                }
            }
        } else if (pid > 0) {
            do {
                wpid = waitpid(pid, &status, WUNTRACED);
            } while (!WIFEXITED(status) && !WIFSIGNALED(status));
        }
    } else {
        int pid = fork(), wpid;
        int status;
        const char *rest = res[0].c_str();

        if (pid == 0) {
            char **cmd_temp = new char *[res.size()];
            char *env[] = {0, NULL};
            for (int i = 0; i < res.size(); i++) {
                cmd_temp[i] = new char[500];
                memset(cmd_temp[i], 0, sizeof(cmd_temp[i]));
            }
            for (int i = 0; i < res.size(); i++) {
                strcpy(cmd_temp[i], res[i].c_str());
            }
            cmd_temp[res.size()] = NULL;
            if (execvp(rest, cmd_temp) < 0) {
                printf("\033[31m%s:command not found.\n\033[0m", res[0].c_str());
            }
        } else if (pid > 0) {
            do {
                wpid = waitpid(pid, &status, WUNTRACED);
            } while (!WIFEXITED(status) && !WIFSIGNALED(status));
        }
    }
    return SUCCESS;
}

vector<string> split(const string &s, const string &separator) {
    vector<string> result;
    typedef string::size_type string_size;
    string_size i = 0;
    while (i != s.size()) {
        int flag = 0;
        while (i != s.size() && flag == 0) {
            flag = 1;
            for (string_size x = 0; x < separator.size(); ++x)
                if (s[i] == separator[x]) {
                    ++i;
                    flag = 0;
                    break;
                }
        }
        flag = 0;
        string_size j = i;
        while (j != s.size() && flag == 0) {
            for (string_size x = 0; x < separator.size(); ++x)
                if (s[j] == separator[x]) {
                    flag = 1;
                    break;
                }
            if (flag == 0)
                ++j;
        }
        if (i != j) {
            result.push_back(s.substr(i, j - i));
            i = j;
        }
    }
    return result;
}

int main() {
    string cmdstring;
    printf("\033[32m************** welcome to mini shell ************** \n\033[0m");

    strcpy(current_dir, getpwuid(getuid())->pw_dir);
    strcpy(user_dir, getpwuid(getuid())->pw_dir);
    printf("\033[92m%s@MINISHELL\033[0m:\033[34m%s\033[0m$", getlogin(), current_dir);

    while (1) {
        for (int i = 0; i < re.size(); i++) {
            re[i].clear();
        }

        getline(cin, cmdstring);
        string result;
        vector<string> v = split(cmdstring, ";");

        for (int i = 0; i < v.size(); i++) {
            re.clear();
            stringstream input2(v[i]);
            while (input2 >> result) {
                re.push_back(result);
            }

            if (result == "exit") {
                printf("\033[32m****************** mini shell exit ******************\n\033[0m");
                return 0;
            }

            if (re.size()) {
                eval(re);
            }
        }

        printf("\033[92m%s@MINISHELL\033[0m:\033[34m%s\033[0m$", getlogin(), current_dir);
    }

    return 0;
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Roc.lp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值