[GNU/Linux] 自己实现shell

本文介绍了尝试自己实现一个简单的GNU/Linux shell的过程,包括源代码结构、注意事项等。通过这个项目,可以学习和熟悉进程相关的内核函数。文章强调了在父进程中正确处理子进程结束的重要性,以及在构建过程中避免特定错误的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

shell作为一种与内核对话的一种方式,为我们使用操作系统服务,提供了很多便利。在我们使用Linux时,shell是不得不接触的内容之一。为了学习和熟悉Linux进程相关的内核函数,我们可以尝试着自己实现一个shell

源代码

src/Makefile

SOURCES = $(wildcard *.cpp)
OBJECTS = $(patsubst %.cpp, %.o, $(SOURCES))
CXXFLAG = -std=c++14 -I ../include -O2 -lreadline

psh: $(OBJECTS)
    g++ $(CXXFLAG) -o psh $(OBJECTS)

$(OBJECTS): $(SOURCES)
    g++ $(CXXFLAG) -c $(SOURCES)

.PHONY: clean
clean :
    -rm $(OBJECTS)

include/psh.h

#pragma once
#ifndef _HEADER_PANGDA_SHELL__
#define _HEADER_PANGDA_SHELL__

#include<unistd.h>
#include<cstdio>
#include<string>
#include<vector>
#include<functional>
#include<map>

typedef std::vector<std::string> argument_t;

struct command_t {
    int is_right_cmd = 0;               //命令是否是正确的,若为0则说明是正确的,其他数字代表错误码
    std::string execfile;               //执行的文件名
    argument_t arguments;               //参数列表
    bool is_redirect_stdin = false;     //是否重定向了标准输入,即是否存在<语法元素
    std::string filename_in;            //新的标准输入名
    bool is_redirect_stdout = false;    //是否重定向了标准输出,即是否存在>语法元素
    bool stdout_mode = false;           //false表示截断输出,true表示追加输出
    std::string filename_out;           //新的标准输出文件名
    bool is_background = false;         //是否指定在后台运行,即是否存在&语法元素
    bool is_pipe = false;               //是否是一个管道,即是否存在|语法元素
    std::string pipe_prompt[2];         //保存管道命令
};

command_t parse_command(std::string command);
std::string string_trim(std::string s);
std::string get_tip();
int exec_command(command_t &cmd);
int psh_error(int error);
int shellfunc_exit(command_t);
int shellfunc_logout(command_t);
int shellfunc_cd(command_t);

#endif

src/psh.cpp

#include<pangda/psh.h>
#include<readline/readline.h>
#include<readline/history.h>
#include<cstdlib>
#include<signal.h>
extern std::map<std::string, std::function<int(command_t)> > shell_commands;

int main(int argc, char *argv[], char **envp) {
    //构建内建命令与实现函数的映射
    shell_commands["exit"] = shellfunc_exit;
    shell_commands["logout"] = shellfunc_logout;
    shell_commands["cd"] = shellfunc_cd;

    //阻断SIGINT SIGQUIT SIGSTOP SIGTSTP
    signal(SIGINT, SIG_IGN);
    signal(SIGQUIT, SIG_IGN);
    signal(SIGSTOP, SIG_IGN);
    signal(SIGTSTP, SIG_IGN);
    while (true) {
        std::string st = readline(get_tip().c_str());   //获得用户输入的内容
        //若用户输入的不是全空格,则将这条命令保存在历史记录中。
        //否则就不处理这条命令,直接获得下一条命令。
        if (string_trim(st) == "")
            continue;
        else
            add_history(st.c_str());

        //解析命令
        command_t cmd = parse_command(st);

        //若命令是管道,则分别执行两条管道命令
        if (cmd.is_pipe) {
            command_t pipe1 = parse_command(cmd.pipe_prompt[0]);
            command_t pipe2 = parse_command(cmd.pipe_prompt[1]);
            if (exec_command(pipe1) != 0)   //若管道的第一条命令就是错误的,不再执行第二条命令
                continue;
            exec_command(pipe2);
        } else if (cmd.is_right_cmd) {  //若解析命令之后发现命令存在错误,则进入错误处理程序
            psh_error(cmd.is_right_cmd);
            continue;
        }
        exec_command(cmd);      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值