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

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fantasy`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值