带历史功能的UNIX Shell

一、项目背景与目标

本实验旨在通过设计一个C程序来实现一个具有历史功能的UNIX Shell接口。该程序将接受用户输入的命令,并在单独的进程中执行每个命令。用户输入的命令将被解析为令牌,并存储在字符字符串数组中,随后由execvp()函数执行。此外,该程序还将实现一个历史功能,允许用户访问最近输入的命令。

二、项目设计与实现

1.创建子进程并执行命令

首先,修改main()函数,使其能够分叉一个子进程并执行用户指定的命令。使用fork()系统调用来创建子进程,并在子进程中调用execvp()函数来执行命令。为了解析用户输入的命令,我将其拆分为令牌,并存储在args数组中。该数组随后被传递给execvp()函数。
我们还需要检查用户是否在命令末尾添加了&符号,以确定父进程是否应该等待子进程退出。如果用户添加了&符号,则父进程将继续执行,而不会等待子进程完成。

2.实现历史功能

接下来,修改Shell接口程序,使其提供历史功能。该程序维护了一个包含最近10条命令的历史缓冲区。用户可以通过输入“History”命令来列出最近输入的命令。命令将按从最近到最旧的顺序编号。
还需要实现两种从命令历史中检索命令的技术:
当用户输入!!时,将执行历史中最近的命令。
当用户输入一个单感叹号后跟一个整数N时,将执行历史中的第N条命令。
任何以这种方式执行的命令都将在用户的屏幕上回显,并放置在历史缓冲区中作为下一条命令。
添加基本的错误处理功能。如果历史中没有命令,输入!!将显示消息“No commands in history.”。如果输入的单感叹号后跟的整数N没有对应的命令,则程序将输出“No such command in history.”。

三、实验结果与分析

通过多次运行程序并输入各种命令来测试Shell的功能。以下是部分实验结果:
输入命令“cat prog.c”并回车,程序正确显示了文件prog.c的内容。
输入命令“ls -l &”并回车,程序在后台列出了当前目录的内容,并立即返回了提示符。
输入命令“History”并回车,程序列出了最近输入的10条命令。
输入“!!”并执行了最近的一条命令。
输入“!3”并执行了历史中的第三条命令。
我们还注意到,在程序运行期间,如果输入的命令无效或无法执行,程序会正确地显示错误信息,并继续等待用户的下一个输入。

四、遇到的问题与解决方案

在项目实施过程中,我遇到了以下问题:
在解析用户输入的命令时,我发现需要正确地处理空格和特殊字符。为此,我使用了strtok()函数来拆分输入字符串,并使用isspace()函数来检查字符是否为空格。
在实现历史功能时,需要确保历史缓冲区的大小足够容纳最近10条命令。我使用了循环数组来实现这一点,当达到数组末尾时,会从数组的开头开始覆盖旧命令。
在处理后台进程时,需要确保父进程不会等待所有子进程都完成后再继续执行。为此,我在创建子进程后立即检查了命令中是否包含&符号,并相应地调整了父进程的等待行为。

五、建议与评论

通过本项目,我加深了对操作系统shell和系统调用的理解,并学会了如何创建进程并协调父进程和子进程的运行。此外,我还学会了如何实现简单的历史功能来增强用户体验。我认为这是一个非常有价值且有趣的项目,它让我们在实践中深入了解了UNIX Shell的工作原理。

六、源代码附录

// Project 01 UNIX Shell with History Feature.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include   
#include   
#include   
#include   
#include <sys/types.h>  
#include <sys/wait.h>  

#define MAX_LINE 80  
#define MAX_HISTORY 10  

char* history[MAX_HISTORY];
int history_count = 0;

void add_to_history(char* command) {
    if (history_count < MAX_HISTORY) {
        history[history_count++] = strdup(command);
    }
    else {
        for (int i = 0; i < MAX_HISTORY - 1; i++) { history[i] = history[i + 1]; } history[MAX_HISTORY - 1] = strdup(command); } } void list_history() { printf("Command history:\n"); for (int i = history_count - 1; i >= 0 && i >= history_count - MAX_HISTORY; i--) {
        printf("%d %s\n", history_count - i, history[i]);
    }
}

void execute_history_command(char* input) {
    if (strcmp(input, "!!") == 0) {
        if (history_count > 0) {
            char* command = history[history_count - 1];
            printf("Executing: %s\n", command);
            add_to_history(command); // Place the command back in history as the next command  
            char* args[MAX_LINE / 2 + 1];
            parse_command(command, args);
            execute_command(args);
        }
        else {
            printf("No commands in history.\n");
        }
    }
    else if (input[0] == '!' && isdigit(input[1])) {
        int index = atoi(input + 1);
        if (index > 0 && index <= history_count) {
            char* command = history[history_count - index];
            printf("Executing: %s\n", command);
            add_to_history(command); // Place the command back in history as the next command  
            char* args[MAX_LINE / 2 + 1];
            parse_command(command, args);
            execute_command(args);
        }
        else {
            printf("No such command in history.\n");
        }
    }
}

void parse_command(char* line, char** args) {
    char* token = strtok(line, " \t\r\n\a");
    int i = 0;
    while (token != NULL && i < MAX_LINE / 2) { args[i++] = token; token = strtok(NULL, " \t\r\n\a"); } args[i] = NULL; } void execute_command(char** args) { pid_t pid = fork(); if (pid == 0) { // Child process if (execvp(args[0], args) == -1) { perror("execvp"); exit(EXIT_FAILURE); } } else if (pid > 0) {
        // Parent process  
        if (strchr(args[0], '&') == NULL) {
            wait(NULL); // Wait for the child process to exit  
        }
    }
    else {
        // Fork failed  
        perror("fork");
        exit(EXIT_FAILURE);
    }
}

int main() {
    char line[MAX_LINE];
    int should_run = 1;

    while (should_run) {
        printf("osh> ");
        fflush(stdout);

        if (fgets(line, MAX_LINE, stdin) == NULL) {
            perror("fgets");
            exit(EXIT_FAILURE);
        }

        // Remove newline character at the end of the input  
        line[strcspn(line, "\n")] = 0;

        // Check for exit command  
        if (strcmp(line, "exit") == 0) {
            should_run = 0;
        }
        else if (line[0] == '!' && (line[1] == '!' || isdigit(line[1]))) {
            // Handle history commands  
            execute_history_command(line);
        }
        else {
            // Normal command  
            char* args[MAX_LINE / 2 + 1];
            parse_command(line, args);

            // Check for background execution  
            int bg = 0; // By default, not running in background  
            if (args[argc(args) - 1] && strcmp(args[argc(args) - 1], "&") == 0) {
                bg = 1;
                args[argc(args) - 1] = NULL; // Remove '&' from arguments  
            }

            execute_command(args);

            // If not running in background, wait for command to complete  
            if (!bg) {
                wait(NULL); // Reap any zombie processes  
            }

            // Add the command to history  
            add_to_history(line);
        }
    }

    // Free allocated memory for history commands  
    for (int i = 0; i < history_count; i++) {
        free(history[i]);
    }

    return 0;
}

// Helper function to get the number of arguments in an argv-like array  
int argc(char** args) {
    int count = 0;
    while (args[count] != NULL) {
        count++;
    }
    return count;
}
作者:星尘旅人
1.本网站部分素材来源于网络,仅供大家参考学习,如有侵权,请联系博主删除处理。
2.本网站一切内容不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
3.版权&许可请详阅版权声明
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
//音乐播放