用C语言写一个自己的shell-Part Ⅱ--execute commands

news/2024/7/5 3:08:43

Part Ⅱ–execute commands

Exec

This brings us to the exec family of functions. Namely, it has the following functions:

  • execl
  • execv
  • execle
  • execve
  • execlp
  • execvp

For our needs,we will use execvp whose signature looks like this

int execvp(const char *file, char *const argv[]);

execvp function indicates that,it accepts the name of a file,for which it will search for $PATH variable of the system and an array of arguments to be executed.

A few things to note about the execvp function:

  1. The first argument is the name of the command
  2. The second argument consists of the name of the command and the arguments passed to the command itself. It must also be terminated by NULL.
  3. It also swaps out the current process image with that of the command being executed, but more on that later.

execvp.c

#include <unistd.h>

int main() {
    char *argv[] = {"ls","-l","-h","-a",NULL};
    execvp(argv[0],argv);

    return 0;
}

If you compile and execute the execvp.c, you will see an output similar to the following:

total 32K
drwxrwxr-x 2 marco marco 4.0K  3月  1 22:07 .
drwxrwxr-x 5 marco marco 4.0K  3月  1 22:04 ..
-rwxrwxr-x 1 marco marco  17K  3月  1 22:07 execvp
-rw-rw-r-- 1 marco marco  123  3月  1 22:07 execvp.c

Which is exactly the same if you manually executels -l -h -a

readline

https://tiswww.case.edu/php/chet/readline/rltop.html

With execvp function,we can perform commands in $PATH but how to accept the string of commands as stdin?

This brings us to the Readline Library.

#include <stdio.h>
#include <readline/readline.h>
char * readline (const char *prompt);

However,when I used this function,error occured.

Ubuntu that I used doesn’t have the library by default.Hence,the library need to be installed.

sudo apt-get install libreadline-dev

Meanwhile,we should add an another argument to link the library when compiling the File.c ,otherwise you may see an error like

“undefined reference to `readline’
collect2: error: ld returned 1 exit status”.

gcc File.c -o File -lreadline

And here’s the code.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <readline/readline.h>
#include <sys/wait.h>

char **get_input(char *);

int main() {
    //in C,ptr can be used as array.
    char **command;
    char *input;
    pid_t child_pid;
    int stat_loc;

    while(1) {
        input = readline("mysh> ");//with "mysh> " to be a prompt,the function reads a line of input.
        command = get_input(input);

        if(!command[0]) {//empty commands
            free(input);
            free(command);
            continue;
        }

        child_pid = fork();
        if(child_pid == 0) {
            //child process
            execvp(command[0],command);
        } else {
            waitpid(child_pid, &stat_loc, WUNTRACED);
        }

        free(input);
        free(command);
    }

    return 0;
}

char **get_input(char *input) {
    char **command = malloc(8 * sizeof(char *));
    char *separator = " ";
    char *parsed;
    int index = 0;

    parsed = strtok(input, separator);
    while (parsed != NULL) {
        command[index] = parsed;
        index++;

        parsed = strtok(NULL, separator);
    }

    command[index] = NULL;
    return command;
}

Let’s test it.

在这里插入图片描述

However,the exec family of function can’t perform built-in commands like cd.

在这里插入图片描述

The code with weak robustness should be revised to be more robust and stronger.

  1. Dynamic memory allocation - in char ** get_input(char *input);

    The command variable only malloc 8 sizeof(char *).It’s limited,

    so you will see the following error:

在这里插入图片描述

To handle the error,commandshould malloc dynamic memories.

  1. fork failed - If the OS runs out of memory or reaches the maxmum number of allowed processes,a child process will not be created.We add the following segment to our code:

    		if(child_pid < 0) {
                perror(command[0]);
                exit(1);
            }
    
  2. exev failed - the exev function may fail.We modify the following block to our code:

    			//child process
                if (execvp(command[0], command) < 0) {
                    perror(command[0]);
                    exit(1);
                }
    

The revised code is here,written by chatGPT.The AI is amazing!!!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <readline/readline.h>
#include <sys/wait.h>

char **split_input(char *);

int main() {
    //in C,ptr can be used as array.
    char **command;
    char *input;
    pid_t child_pid;
    int stat_loc;

    while(1) {
        input = readline("mysh> ");//with "mysh> " to be a prompt,the function reads a line of input.
        command = split_input(input);

        if(!command[0]) {//empty commands
            free(input);
            free(command);
            continue;
        }

        //fork failed.
        child_pid = fork();
        if(child_pid < 0) {
            perror(command[0]);
            exit(1);
        }

        if(child_pid == 0) {
            //child process
            if (execvp(command[0], command) < 0) {
                perror(command[0]);
                exit(1);
            }
        } else {
            waitpid(child_pid, &stat_loc, WUNTRACED);
        }

        free(input);
        free(command);
    }

    return 0;
}
char **split_input(char *input) {
    int capacity = 10;
    char **command = malloc(capacity * sizeof(char *));
    if (command == NULL) {
        fprintf(stderr, "Error: memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    char *token = strtok(input, " ");
    int i = 0;
    while (token != NULL) {
        if (i == capacity - 1) {  // resize the array if it is full
            capacity *= 2;
            char **new_command = realloc(command, capacity * sizeof(char *));
            if (new_command == NULL) {
                fprintf(stderr, "Error: memory allocation failed\n");
                exit(EXIT_FAILURE);
            }
            command = new_command;
        }

        command[i] = malloc((strlen(token) + 1) * sizeof(char));
        if (command[i] == NULL) {
            fprintf(stderr, "Error: memory allocation failed\n");
            exit(EXIT_FAILURE);
        }
        strcpy(command[i], token);
        token = strtok(NULL, " ");
        i++;
    }
    command[i] = NULL;  // terminate the array with NULL

    return command;
}

http://lihuaxi.xjx100.cn/news/956764.html

相关文章

学习大数据应该掌握哪些技能

想要了解大数据开发需要掌握哪些技术&#xff0c;不妨先一起来了解一下大数据开发到底是做什么的~ 1、什么是大数据&#xff1f; 关于大数据的解释&#xff0c;比较官方的定义是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模…

Kubernetes-in-action (七)

Kubernetes-in-action (七) 本节内容&#xff1a;Deployment&#xff0c;StatefulSet Deployment 作用 作为RC和RS的高一级资源 [RC -> replicationController, RS -> ReplicaSet]可以让pod 模板变化后立即生效&#xff0c;不需要手动重启pod来让配置生效。 (会自动删除…

基于Qt不同开发平台的编码设置(解决中文编码问题)

目录 1.引言 2. 具体步骤 2.1 不同开发环境配置 2.1.1 IDE是Qt Creator 2.1.2 如果IDE是Visual Studio 2.1.3 如果编译器是MSVC 2.2 源码文件main函数入口设置中文编码&#xff1a; 1.引言 Qt的编码向来是比较让人头疼的事情&#xff0c;尤其是涉及跨平台方面的中文…

Java并发简介(什么是并发)

文章目录并发概念并发和并行同步和异步阻塞和非阻塞进程和线程竞态条件和临界区管程并发的特点提升资源利用率程序响应更快并发的问题安全性问题缓存导致的可见性问题线程切换带来的原子性问题编译优化带来的有序性问题保证并发安全的思路互斥同步&#xff08;阻塞同步&#xf…

招募生态合作伙伴该注意什么?

在当今竞争激烈的商业环境中&#xff0c;拥有优秀的合作伙伴可以为企业带来巨大的价值。合作伙伴可以提供更多的资源、知识和经验&#xff0c;帮助企业扩大市场份额、增加收益和降低风险。因此&#xff0c;招聘合适的合作伙伴对企业的成功至关重要。在制定合作伙伴招聘策略时&a…

RK3288-android8-IR-选不中小窗口

IR红外功能,多么基础的功能,但是说来也不简单 因为,小小的红外看似基础,实则设计太多东西了, 从关机涉及Uboot;到内核kernel键码上报;到android键码的实现,小小的功能涉及大大的范围; (101条消息) rk3288-android8-IR-mouse_旋风旋风的博客-CSDN博客 大家可以看一下我之前的…

Java之注解

注解1.1 注解的概念1.2 内置注解1.3 元注解1.4 自定义注解1.1 注解的概念 Annotation 是从JDK5.0 开始引入的新技术 Annotation的作用&#xff1a; 不是程序本身&#xff0c;可以对程序做出解释&#xff08;这一点和注释comment没什么区别&#xff09;可以被其他程序&#xff…

子数组达到规定累加和的最大长度系列问题

文章目录1、题目一&#xff1a;正整数数组中子数组累加和 KKK 最大长度1.1 题目描述1.2 思路分析1.3 代码实现2、题目二&#xff1a;整数数组中子数组累加和为 KKK 的最大长度2.1 题目描述2.2 思路分析2.3 代码实现2.4 引申变形2.5 技巧应用题2.5.1 剑指 Offer II 010. 和为 k …