Linux下简单Shell实现(三)获取任务列表

本文详细介绍了如何在Linux Shell中实现获取并处理任务列表的功能。通过读取用户输入的命令行,按行存储到任务队列中,遵循先进先出的原则。遇到后台执行标志'&'时调整执行状态,利用管道符号'|'拆分命令,将每个进程作为独立任务存入队列。文章以实例解析了处理流程,帮助理解Shell如何管理任务。

如果看过上一篇的话,还会记得在本Shell中main函数内第一条实质性的指令是

getTaskList(task_queue);

在本节,就会讲解这个获取任务列表,并存储到任务队列中的函数,到底在干什么。
我先把整个函数摆在下面,然后逐一讲解(先不要看下面这一大段代码)

void getTaskList(queue<string> & task_queue)
{
    while(!task_queue.empty()) task_queue.pop();

    string command_line;
    getline(cin, command_line);

    if(cin.eof())
    {
        exit(0);
    }   

    if(command_line.empty())
        return;

    if(command_line.back() == '&')
    {
        getIfDetach() = true;
        command_line.erase(command_line.end() - 1);

        if(command_line.empty())
            return;
    }
    else
    {
        getIfDetach() = false;
    }

    auto base_iter = command_line.begin();

    for(auto off_iter = command_line.begin(); off_iter != command_line.end(); ++ off_iter )
    {
        if(*off_iter == '|')
        {
            if(off_iter != command_line.begin() && *(off_iter - 1) == '\\')
            {
                off_iter = command_line.erase(off_iter - 1);
                continue;
            }
            task_queue.push(string(base_iter, off_iter));
            base_iter = off_iter + 1;
        }
    }

    task_queue.push(string(base_iter, command_line.end()));
    return;
}

首先函数原型为:

void getTaskList(queue<string> & task_queue);

传入一个std::queue<string>的引用,并把读到的指令按先后顺序存入队列中,之所以使用队列的结构是为了方便使用时先进先出的逻辑。

while(!task_queue.empty()) task_queue.pop();

上述代码块用于检测传入的指令队列是否为空,如果不为空,则将其pop至空,主要是queue没有vector等结构的clear函数,比较麻烦。

    string command_line;
    getline(cin, command_line);

    if(cin.eof())
    {
        exit(0);
    }   

一般Shell中命令都是一行一行输入的,因此读入一行命令,存入command_line是本Shell的获取命令的方式。同时,如果输入ctrl+d也就是文件结束符的话,则退出Shell(模仿bash)。

    if(command_line.empty())
        return;

    if(command_line.back() == '&')
    {
        getIfDetach() = true;
        command_line.erase(command_line.end() - 1);

        if(command_line.empty())
            return;
    }
    else
    {
        getIfDetach() = false;
    }

如果读入的命令行为空的话,直接返回。
如果读入的命令行的最后一个字符为’&’的话,则说明本次输入的命令行为后台执行,将getIfDetach()函数内的static变量Detach置为true,并调用string类的erase函数删除最后的&字符。同时,如果删除&后命令行为空的话,说明用户仅输入了一个&字符,那么也直接返回。
如果最后一个字符不为’&’,则将Detach变量置为false。

    auto base_iter = command_line.begin();

    for(auto off_iter = command_line.begin(); off_iter != command_line.end(); ++ off_iter )
    {
        if(*off_iter == '|')
        {
            if(off_iter != command_line.begin() && *(off_iter - 1) == '\\')
            {
                off_iter = command_line.erase(off_iter - 1);
                continue;
            }
            task_queue.push(string(base_iter, off_iter));
            base_iter = off_iter + 1;
        }
    }

这一段可能比较难以理解,实际上我们在做的事情是,当用户使用管道调用多个进程时,我们需要把这几个进程从命令行中分开,然后分别存入task_queue中。首先让base_iter为command_line的头迭代器。托C++11的福,一个auto关键字真是解放劳动力。
接下来让off_iter从命令行头至命令行尾遍历,每当发现一个|字符(也就是管道的调用标识),则将base_iter至off_iter之间的字符串存入task_queue中,同时更新base_iter为off_iter的下一个。
如下图所示,给出了以`ls | grep main | more为例的处理流程:
这里写图片描述
注:task_queue中存储的命令是以进程为最小单位,也就是命令行参数和进程是作为同一个任务存到该队列中,并没有分开,如本例中的grep main

    task_queue.push(string(base_iter, command_line.end()));

最后将最后一段命令存入任务列表,即完成该函数全部工作。也就是上例中存入more的步骤。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值