【Linux】进程_9

简介: 【Linux】进程_9

五、进程

12. 自定义shell

根据我们之前学的知识,这里来编写一个 shell 程序。

#include<stdio.h>                                                                                  
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#define SIZE 1024
#define MAX_ARGC 64
 
// 用户名
const char* UserName()
{
    char* username = getenv("USER");
    if (username) return username;
    else return "None";
}
// 主机名
const char* HostName()
{                                         
    char* hostname = getenv("HOSTNAME");    
    if (hostname) return hostname;          
    else return "None";                     
}                                         
// 路径                                   
const char* CurrentWorkDir()              
{                                         
    char* currentworkdir = getenv("PWD");   
    if (currentworkdir) return currentworkdir;
  else return "None";
}

上面代码可以通过环境变量接口获取指定信息。我们先输出一下命令行提示符试试看。

封装输出命令行提示符的信息和接收用户输入成一个函数。

我们获取到了用户一行输入的整个字符串,现在需要对这个字符串进行切割。

// 分隔符是空格
#define SEP " "
void Split(char in[])
{
    int i = 0;
    argv[i++] = strtok(in, SEP);
    while (argv[i++] = strtok(NULL, SEP));
 }

当做完以上操作后就可以执行命令了,我们创建一个子进程,让子进程来程序替换为我们要执行的命令。我们封装一下执行命令。

我们不想自己写的shell程序只跑一遍,所以我们要在主函数里加上死循环。

运行比较成功,但是我们发现,使用 cd … 命令却没有反应,这是怎么回事?因为执行cd命令的是子进程而不是我们的shell 。像这种不让子进程来执行的命令,而是让我们的shell执行的命令叫做 内建命令 。我们需要特殊处理一下。

// 获取环境变量
char *Home()
{
    return getenv("HOME");
}
int BuildinCmd()
{
    // 是内建命令则返回1,不是则返回0
    int ret = 0;
    if (strcmp("cd", argv[0]) == 0)                                                                  
    {
        ret = 1;
        char *target = argv[1];
        // cd 空表示进入家目录
        if (!target) target = Home();
        chdir(target);
    }
    return ret;
}

我们再来测试一下:

这里已经完成的差不多了,再来处理一下细节问题,比如环境变量没有更新。

// 记录路径字符
char pwd[SIZE];
int BuildinCmd()
{
    int ret = 0;
    if(strcmp("cd", argv[0]) == 0)
    {
        ret = 1;
        char *target = argv[1];
        if(!target) target = Home();
        chdir(target);
        char temp[1024];
        // 获取当前路径
        getcwd(temp, 1024);
        // 写入数组
        snprintf(pwd, SIZE, "PWD=%s", temp);
        // 更新
        putenv(pwd);
    }
}

再来测试一下:

比较完善了。但是实际上内建命令绝对不止 cd 命令,至少还包含 exportecho 等命令。就不再一一赘述了。感兴趣的可以自己再去完善,也可以使ls命令带上颜色等等。

完整程序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
 
#define SIZE 1024
#define MAX_ARGC 64
#define SEP " "
 
char *argv[MAX_ARGC];
char pwd[SIZE];
// 用户名
const char* UserName()
{
    char* username = getenv("USER");                                                                 
    if (username) return username;
    else return "None";
}
// 主机名
const char* HostName()
{
    char* hostname = getenv("HOSTNAME");
    if (hostname) return hostname;
    else return "None";                                                                              
}
// 路径
const char* CurrentWorkDir()
{
    char* currentworkdir = getenv("PWD");
    if (currentworkdir) return currentworkdir;
    else return "None";
}
// 家目录
char* Home()
{
    return getenv("HOME");
}
int Interactive(char out[], int size)
{
    // 输出命令行提示符
    printf("[%s@%s %s]$ ", UserName(), HostName(), CurrentWorkDir());
    // 接收用户输入
    fgets(out, size, stdin);
    // 去掉最后一个 回车符                                                                           
    out[strlen(out) - 1] = '\0';
    return strlen(out);
}
void Split(char in[])
{
    int i = 0;
    argv[i++] = strtok(in, SEP);
    while (argv[i++] = strtok(NULL, SEP));
}
void Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        // 让子进程执行命令 文件名 + 选项数组
        execvp(argv[0], argv);                                                                     
        exit(1);
    }
    waitpid(id, NULL, 0);
}
int BuildinCmd()
{
    // 是内建命令则返回1,不是则返回0
    int ret = 0;
    if (strcmp("cd", argv[0]) == 0)
    {
        ret = 1;
        char *target = argv[1];
        // cd 空表示进入家目录
        if (!target) target = Home();
        chdir(target);
        char temp[SIZE];
        getcwd(temp, SIZE);
        snprintf(pwd, SIZE, "PWD=%s", temp);
        putenv(pwd);
    }                                                                                                
    return ret;
}
int main()
{
    while(1)
    {
        char commandline[SIZE];
        int n = Interactive(commandline, SIZE);
        // 空串跳出
        if (n == 0) continue;
        Split(commandline);
        n = BuildinCmd();
        if (n) continue;
        Execute();
    }
    return 0;
}

未完待续

目录
相关文章
|
27天前
|
资源调度 Linux 调度
Linux c/c++之进程基础
这篇文章主要介绍了Linux下C/C++进程的基本概念、组成、模式、运行和状态,以及如何使用系统调用创建和管理进程。
29 0
|
3月前
|
网络协议 Linux
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
571 2
|
3月前
|
Linux Python
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
64 2
|
2天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
19 4
linux进程管理万字详解!!!
|
1天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
15 4
|
2天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
3天前
|
消息中间件 存储 Linux
|
10天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
10 1
|
21天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
【10月更文挑战第9天】本文将深入浅出地介绍Linux系统中的进程管理机制,包括进程的概念、状态、调度以及如何在Linux环境下进行进程控制。我们将通过直观的语言和生动的比喻,让读者轻松掌握这一核心概念。文章不仅适合初学者构建基础,也能帮助有经验的用户加深对进程管理的理解。
16 1
|
27天前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
23 0
Linux c/c++之IPC进程间通信