Unix外壳和历史特征

Topic:

Unix外壳和历史特征

 

Requirements:

Part1 创建子进程

  1. 拆分用户输入为多个标记,并将这些标记存到字符串args[]数组中。
  2. fork()创建一个子进程
  3. 子进程调用execvp(char*command,char *params[])函数执行用户指定命令
  4. 检查数组最后一个位置是否有&,以便确定是否等待子进程

Part2 创建历史功能

1、允许用户访问最近输入的命令,通过这个功能用户最多可以访问10个命令,在osh>后面输入history,用户能够累出历史命令

2、当用户输入!!时,将会执行最近的历史命令,如果没有历史命令,应当产生消息“No commands in history”

3、当用户输入!和一个整数n之后,将执行第N个历史命令,如果没有历史命令,应当产生消息“No such command in history”

Procedure

1、先要实现将输入的命令分割,这里用args(char* args[])数组来存放分割后的标志,例如ls –al, 每次输入下一个命令之前数组的内容清空,存储形式如下:

  args[0]=ls

  args[1]=-al

 

do {

            char* s = (char*)malloc(128);

            scanf("%s", s);//输入空格或者回车换行结束

            c = getchar();

            args[i] = s;

            h[num % 10].args[i++] = s;

            if (strcmp(args[0], "exit") == 0) { should_run = 0; }//用户在提示符后面输入exit后,should_run0并且终止;

            if (strcmp(args[i - 1], "&") == 0) { i--; } //输入& 显示waitpidsuccess

        } while (c == ' '); //如果是空格继续循环

        args[i] = NULL; h[num%10].args[i] = NULL;//数组的结束位置

 

2、调用fork()函数创建子进程,并将args[]数组内的命令给execvp(args[0], args)函数

        pid_t id = fork(); //创建子进程,父进程和子进程之间共享代码段(建立相同的程序副本)

        if (id < 0) {

            perror("fork");    //抛出异常

        }

        if (id == 0) {

            execvp(args[0], args);   //exec系列的一种,用于运行新程序

            exit(1);               //调用exit()来终止程序

        }

        else {

            int status = 0;

            pid_t ret = waitpid(id, &status, 0);//等待子进程结束

            if (ret > 0 && WIFEXITED(status))

            {

            }

            else { perror("waitpid"); }

        }

fork()与exec的使用和区别:

系统调用fork():创建子进程,父进程和子进程之间共享代码段(建立相同的程序副本),仅通过复制指令、用户数据和系统数据段来创建从现存进程克隆的新进程,该新进程不是从程序初始化得来的,所以旧进程和新进程执行同样的指令。

系统调用exec():是以新的进程去代替原来的进程,但进程的PID保持不变。也就是exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。

一般使用方法为:先调用fork(),再使用exec()来达到提高效率的目的。

exit():终止进程,如写如exit(1)来结束进程。

系统调用wait():等待子进程的终止。

3、创建一个结构体数组h[10],用以存放历史的十个命令

 struct History

{  

char* args[MAX_LINE/2+1];

}h;

4、每次都将输入的有效命令存入结构体数组h中(数组h是一个循环数组,存满最后一个存储单元后,又从第一个存储单元开始存放,将之前的存储内容覆盖)

5、用户输入的命令存入数组args[]和h[]后,判断当前输入命令的第一个字符串是否是history、!!或者!+N,若满足这三个条件,执行以下命令:

        if (strcmp(args[0], "history") == 0) {

            int count2=0;

            if (!h[count].args[0]) { printf("No commands in history"); }

            while (h[count].args[count2])

            {

                while(h[count].args[count2])

                {

                   printf("%d %s ", count, h[count].args[count2++]);

                }printf("\n");

                count2=0;count++;

            }

        }

        if (strcmp(args[0],"!!") == 0) {

            if (!h[num - 1].args[0]) { printf("No such command in history"); }

            else {

            process(num-1); }

        }

        assume(args); //函数assume实现!加数字执行第N条历史记录的功能

!加数字的历史功能
最近的历史命令和最近输入的命令


 

/**
 * Simple shell interface program.
 *
 * Operating System Concepts - Ninth Edition
 * Copyright John Wiley & Sons - 2013
 */

#include <stdio.h>
#include "unistd.h"
#include<string.h>
#include<stdlib.h>
#include<sys/types.h> /* 提供类型pid_t的定义 */ 
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>/*pid_t wait(int *status)*/
#include <pwd.h>


#define MAX_LINE		80 /* 80 chars per line, per command */
char* args[MAX_LINE / 2 + 1];	/* command line (of 80) has max of 40 arguments */
int should_run = 1;
struct History
{
    char* args[MAX_LINE/2+1];
};
History h[10]; int num = 1;
int assume(char *a[]);
void process(int i);
void play(int i)
{
     int count2=0;
     while(h[i].args[count2++]){
       printf("%s ", h[i].args[count2++]);
     }printf("\n")
}

int main(void)
{
    while (should_run) {
        printf("osh>");//设置提示符为OSH
        fflush(stdout);
        int i = 0, count = 1;
        char c;

        do {
            char* s = (char*)malloc(128);
            scanf("%s", s);//输入空格或者回车换行结束
            c = getchar();
            args[i] = s;
            h[num % 10].args[i++] = s;
            if (strcmp(args[0], "exit") == 0) { should_run = 0; }//用户在提示符后面输入exit后,should_run为0并且终止;
            if (strcmp(args[i - 1], "&") == 0) { i--; } //输入& 显示waitpid:success
        } while (c == ' '); //如果是空格继续循环
        args[i] = NULL; h[num%10].args[i] = NULL;//数组的结束位置

        if (strcmp(args[0], "history") == 0) {
            int count2=0;
            if (!h[count].args[0]) { printf("No commands in history"); }
            while (h[count].args[count2])
            {
                while(h[count].args[count2])
                {
                   printf("%d %s ", count, h[count].args[count2++]);
                }printf("\n");
                count2=0;count++;
            }
        }
        if (strcmp(args[0],"!!") == 0) {
            if (!h[num - 1].args[0]) { printf("No such command in history"); }
            else { 
            play(num-1);
            //pid_t id = fork();execvp(h[num - 1].args[0], h[num - 1].args);
            process(num); }
        }
        assume(args);
        process(num);
        num++;
    }
    return 0;
}
void process(int i)
{
        pid_t id = fork();	//创建子进程,父进程和子进程之间共享代码段(建立相同的程序副本)
        if (id < 0) {
            perror("fork");	//抛出异常
        }
        if (id == 0) {
            execvp(h[i].args[0],h[i]args);   //exec系列的一种,用于运行新程序
            exit(1);				//调用exit()来终止程序
        }
        else {
            int status = 0;
            pid_t ret = waitpid(id, &status, 0);//等待子进程结束
            if (ret > 0 && WIFEXITED(status))
            {
            }
            else { perror("waitpid"); }
        }  
}
void row(int i)
{
       if (!h[i].args[0]) { printf("No such command in history"); }
       else{play(1);//id = fork();execvp(h[1].args[0], h[1].args); exit(1);
       process(i);
       }
}

int assume(char *args[])
{
    pid_t id;
    
    if (strcmp(args[0],"!1")==0) {
       row(1);
    }
    if (strcmp(args[0],"!2")==0) {
       row(2);
       //if (!h[2].args[0]) { printf("No such command in history"); }
       //else{play(2);id = fork();execvp(h[2].args[0], h[2].args); exit(1);}
    }
    if (strcmp(args[0],"!3")==0) {
       row(3);
       //if (!h[3].args[0]) { printf("No such command in history"); }
       //else{play(3);id = fork();execvp(h[3].args[0], h[3].args); exit(1);}
    }
    if (strcmp(args[0],"!4")==0) {
       row(4);
       //if (!h[4].args[0]) { printf("No such command in history"); }
       //else{play(4);id = fork();execvp(h[4].args[0], h[4].args);exit(1);}
    }
    if (strcmp(args[0],"!5")==0) {
       row(5);
       //if (!h[5].args[0]) { printf("No such command in history"); }
       //else{play(5);id = fork();execvp(h[5].args[0], h[5].args); exit(1);}
    }
    if (strcmp(args[0],"!6")==0) {
       row(6);
       //if (!h[6].args[0]) { printf("No such command in history"); }
       //else{play(6);id = fork();execvp(h[6].args[0], h[6].args); exit(1);}
    }
    if (strcmp(args[0],"!7")==0) {
       row(7);
       //if (!h[7].args[0]) { printf("No such command in history"); }
       //else{play(7);id = fork();execvp(h[7].args[0], h[7].args); exit(1);}
    }
    if (strcmp(args[0],"!8")==0) {
       row(8);
       //if (!h[8].args[0]) { printf("No such command in history"); }
       //else{play(8);id = fork();execvp(h[8].args[0], h[8].args); exit(1);}
    }
    if (strcmp(args[0],"!9")==0) {
       row(9);
       //if (!h[9].args[0]) { printf("No such command in history"); }
       //else{play(9);id = fork();execvp(h[9].args[0], h[9].args); exit(1);}
    }
    if (strcmp(args[0],"!10")==0) {
       row(0);
       //if (!h[0].args[0]) { printf("No such command in history"); }
       //else{play(0);id = fork();execvp(h[0].args[0], h[0].args); exit(1);}
    }
    return 0; 
}


猜你喜欢

转载自blog.csdn.net/m0_46785351/article/details/116921820
今日推荐