C++实现模拟shell命令行(代码解析)

 更新时间:2021年12月21日 09:25:52   作者:Jxiepc  
这篇文章主要介绍了C++实现模拟shell命令行,本文通过实例代码进行命令行解析,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

一、解析

/**
 * 进行命令行解析:
 * 多个空格
 * 分割符:< > |
 * */
void parse(){
    std::string line;
    getline(std::cin, line);
    /** 解析字符串 */
    int len = line.size(), i=0;

    std::string tmp;
    std::vector<std::string> tmp_vc;
    while(i < line.size()){
        if(line[i] == ' '){
            i++;
            continue;
        }
        if(line[i] == '|') {
            vc.push_back(tmp_vc);
            tmp = "";
            i++;
            continue;
        }
        int pos = line.find(' ', i);    // 获取下一个空格的位置
        tmp = line.substr(i, pos-i);    // 截取字符串
        tmp_vc.push_back(tmp);
        i = pos;
    }
    vc.push_back(tmp_vc);
}

二、执行命令函数

/** 执行命令子函数 */
void func(std::vector<std::string>& v){
    char *arr[10];
    pid_t pid;
    pid = fork();
    if(pid == -1){
        std::cout << "fork error" << std::endl;
        exit(1);
    }else if(pid ==0){
        for(int i=0; i<v.size(); ++i)
            arr[i] = (char *)v[i].c_str();
        arr[v.size()] = NULL;
        execvp(arr[0], arr);
    }else{
        wait(NULL);
    }
}

/** 执行命令
 * --------
 * 创建子进程执行
 * 当出现|需要创建多个子进程
 * 当出现> <则将内容写入文件或者命令行
 * */
void execCommnd(){
    for(int i=0; i<vc.size(); ++i){
        func(vc[i]);
    }
}

三、模拟shell

/** 获取当前所在目录 */
void getCurPwd(){
    std::string s = get_current_dir_name();
    int pos  = s.rfind('/');
    std::string tmp = s.substr(pos+1, s.length()-pos);
    std::cout << tmp << "]# ";
}

/** 获取当前用户名 */
void getIdname(){
    struct  passwd *pwd;
    pwd = getpwuid(getuid());
    std::cout << "["  <<pwd->pw_name << "@";
}

/** 获取当前主机名 */
void getHostName(){
    char buf_w[128];
    int hostname = gethostname(buf_w, sizeof(buf_w)); 
    std::cout << buf_w << " ";
    
}

/** 显示菜单 */
void showMenu(){
    getIdname();
    getHostName();
    getCurPwd();
}

四、完整代码

/*----------------------------------------------------------------------
	> File Name: shellDemo.cpp
	> Author: Jxiepc
	> Mail: Jxiepc
	> Created Time: Sun 19 Dec 2021 11:24:21 AM CST
----------------------------------------------------------------------*/

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pwd.h>
#include <wait.h>

/* 存储命令以及参数 */
std::vector<std::vector<std::string>> vc;

/**
 * 进行命令行解析:
 * 多个空格
 * 分割符:< > |
 * */
void parse(){
    std::string line;
    getline(std::cin, line);
    /** 解析字符串 */
    int len = line.size(), i=0;

    std::string tmp;
    std::vector<std::string> tmp_vc;
    while(i < line.size()){
        if(line[i] == ' '){
            i++;
            continue;
        }
        if(line[i] == '|') {
            vc.push_back(tmp_vc);
            tmp = "";
            i++;
            continue;
        }
        int pos = line.find(' ', i);                // 获取下一个空格的位置
        tmp = line.substr(i, pos-i);    // 截取字符串
        tmp_vc.push_back(tmp);
        i = pos;
    }
    vc.push_back(tmp_vc);
}

/** 执行命令子函数 */
void func(std::vector<std::string>& v){
    char *arr[10];
    pid_t pid;
    pid = fork();
    if(pid == -1){
        std::cout << "fork error" << std::endl;
        exit(1);
    }else if(pid ==0){
        for(int i=0; i<v.size(); ++i)
            arr[i] = (char *)v[i].c_str();
        arr[v.size()] = NULL;
        execvp(arr[0], arr);
    }else{
        wait(NULL);
    }
}

/** 执行命令
 * --------
 * 创建子进程执行
 * 当出现|需要创建多个子进程
 * 当出现> <则将内容写入文件或者命令行
 * */
void execCommnd(){
    for(int i=0; i<vc.size(); ++i){
        func(vc[i]);
    }
}

/** 获取当前所在目录 */
void getCurPwd(){
    std::string s = get_current_dir_name();
    int pos  = s.rfind('/');
    std::string tmp = s.substr(pos+1, s.length()-pos);
    std::cout << tmp << "]# ";
}

/** 获取当前用户名 */
void getIdname(){
    struct  passwd *pwd;
    pwd = getpwuid(getuid());
    std::cout << "["  <<pwd->pw_name << "@";
}

/** 获取当前主机名 */
void getHostName(){
    char buf_w[128];
    int hostname = gethostname(buf_w, sizeof(buf_w)); 
    std::cout << buf_w << " ";
    
}

/** 显示菜单 */
void showMenu(){
    getIdname();
    getHostName();
    getCurPwd();
}

void test(){
    while(1){
        showMenu();
        parse();
        execCommnd();
    }
}

int main(int argc, char* argv[])
{
    test();
    return 0;
}

四、运行结果

到此这篇关于C++实现模拟shell命令行的文章就介绍到这了,更多相关C++ shell命令行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ Boost Optional示例超详细讲解

    C++ Boost Optional示例超详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • 浅析C++中的函数重载

    浅析C++中的函数重载

    这篇文章主要介绍了浅析C++中的函数重载,在C++中,可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或者参数类型相同而参数个数不同,又或者参数类型参数个数相同,参数次序不同,称为函数重载,需要的朋友可以参考下
    2023-08-08
  • C++隐式转换问题分析及解决办法

    C++隐式转换问题分析及解决办法

    在本篇文章里小编给大家整理了关于C++隐式转换问题分析及解决办法,有需要的朋友们可以学习下。
    2020-02-02
  • C++ Boost实现数字与字符串转化详解

    C++ Boost实现数字与字符串转化详解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • OpenCV实现轮廓的发现

    OpenCV实现轮廓的发现

    这篇文章主要为大家详细介绍了OpenCV如何实现轮廓的发现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • 用c 获取文件MD5值的实现方法

    用c 获取文件MD5值的实现方法

    本篇文章是对用c语言获取文件MD5值的方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++ 超详细示例讲解list的使用

    C++ 超详细示例讲解list的使用

    list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,也就是list也具有链表的主要优点,即:在链表的任一位置进行元素的插入、删除操作都是快速的
    2022-07-07
  • C或C++报错:ld returned 1 exit status报错的原因及解决方法

    C或C++报错:ld returned 1 exit status报错的原因及解

    这篇文章主要介绍了C或C++报错:ld returned 1 exit status报错的原因及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • 一文解析C语言中动态内存管理

    一文解析C语言中动态内存管理

    这篇文章主要为大家详细介绍了C语言中动态内存管理的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • 基于Opencv实现颜色识别

    基于Opencv实现颜色识别

    这篇文章主要为大家详细介绍了基于Opencv实现颜色识别,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07

最新评论