用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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单的C语言实现Shell脚本重定向函数check4redirection和执行函数execute的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #define MAXARGS 20 #define MAXLINE 80 int check4redirection(char *cmd, int *in, int *out) { int i, len, pos = 0; char *args[MAXARGS]; char *infile, *outfile; len = strlen(cmd); for (i = 0; i < len; i++) { if (cmd[i] == '<') { infile = strtok(&cmd[i+1], " \t\n"); *in = open(infile, O_RDONLY); if (*in == -1) { perror("Open file error"); return -1; } cmd[i] = '\0'; } if (cmd[i] == '>') { outfile = strtok(&cmd[i+1], " \t\n"); *out = open(outfile, O_WRONLY|O_TRUNC|O_CREAT, 0644); if (*out == -1) { perror("Open file error"); return -1; } cmd[i] = '\0'; } } args[pos++] = strtok(cmd, " \t\n"); while ((args[pos++] = strtok(NULL, " \t\n")) != NULL); args[pos] = NULL; if (*in != STDIN_FILENO) { if (dup2(*in, STDIN_FILENO) == -1) { perror("Dup2 error"); return -1; } close(*in); } if (*out != STDOUT_FILENO) { if (dup2(*out, STDOUT_FILENO) == -1) { perror("Dup2 error"); return -1; } close(*out); } return execvp(args[0], args); } int execute(char *cmd) { int pid, status, in = STDIN_FILENO, out = STDOUT_FILENO; if ((pid = fork()) == -1) { perror("Fork error"); return -1; } else if (pid == 0) { return check4redirection(cmd, &in, &out); } else { while (wait(&status) != pid); return status; } } int main(int argc, char *argv[]) { char line[MAXLINE]; int status; while (1) { printf("myShell> "); fgets(line, MAXLINE, stdin); if (strcmp(line, "exit\n") == 0) exit(0); status = execute(line); printf("Exit status: %d\n", status); } return 0; } ``` 检查重定向的函数check4redirection接受一个命令字符串,以及两个指针(in和out),用于存储输入和输出的文件描述符。该函数首先使用strtok函数命令字符串拆分为命令和参数数组args,然后在命令字符串中获取输入和输出文件名,并打开相应文件。最后,该函数使用dup2函数将输入和输出文件描述符复制到STDIN_FILENO和STDOUT_FILENO,并关闭原始文件描述符。最后,该函数使用execvp函数执行指定的命令和参数。 执行函数execute接受一个命令字符串并在新进程中调用check4redirection函数。如果fork失败,则返回-1。在子进程中,调用check4redirection函数执行命令。在父进程中,等待子进程执行完毕,并返回子进程的退出状态。主函数使用fgets从标准输入读取命令行,并在循环中执行命令。如果用户输入exit,则退出程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Fantasy`

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

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

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

打赏作者

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

抵扣说明:

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

余额充值