简单的交互式shell(模似shell命令操作)

/**
 * @file myshell.c
 * @Synopsis  
 * 简单的交互式shell
 * 用户输入一行命令 实现和shell 进程一样的效果。。
 * example:
 * cat demo1.txt
 * ps -e
 * ls -lath
 * top
 * who
 * ....
 * 输入上面这些命令和shell 实现一样的效果。
 *
 * 功能:
 * 子父进程使用管道实现命令传输,
 * 命令参数从终端输入,
 * 处理参数,由父进程处理写入管道。
 * 子进程从管道读取传输的命令,
 * 然后交给execlp 处理。
 * 这里也就是交给子进程来处理。
 * 当该子进程调用这个函数时,该进程的用户空间代码和
 * 数据完全被新程序替换(换脑),从新程序的启动例程开始执行。
 *
 * 类似于shell 层。
 * shell 层属于父级,
 * 当用户从终端输入命令时,
 * shell 会调用fork cp 出一个新的shell 进程,
 * 然后新的shell 进程调用 exec 执行新的程序。
 * @author MrClimb
 * @version 1.1.0
 * @date 2012-05-18
 */

#include
#include
#include
#include
#include

int main(int argc, char **argv)
{
    pid_t pid;// 进程编号
    /**
     * pipefd[0] stand for read file description
     * pipefd[1] stand for write file description
     */
    int pipefd[2];// 文件描述符
    char buffer[BUFSIZ];//1024*8 = 8192 
    char *arguments[BUFSIZ];
    size_t st;
    ssize_t sst;

while(1){

    printf("input shell(exit):");
    
    memset(buffer,0,BUFSIZ);
    /**
     * create pipe
     * int pipe(int pipefd[2]);
     * 创建管道
     * 传出两个参数
     */
    if(pipe(pipefd)==-1)
    {
        perror("cannot create pipe");
        exit(1);
    }
    
    char param1[BUFSIZ];
    char inputp[BUFSIZ];
    memset(inputp,0,BUFSIZ);
    // 获得终端的命令输入
    fgets(inputp,BUFSIZ,stdin);
    // 处理 \n 字符 但这里不完全正确。。
    inputp[strlen(inputp)-1]='\0';
    
    if(strcmp(inputp,"exit")==0)
    {
        exit(1);
    }
    
    int i=0;
    char *sep = strtok(inputp," ");
        strcpy(buffer,sep);

    int len1 = strlen(buffer);
    arguments[0] = (char *)malloc(len1+1);
    strcpy(arguments[0],buffer);
    i++;
    while((sep=strtok(NULL," "))!=NULL)
    {
        len1 = strlen(buffer);
        arguments[i] = (char *)malloc(len1+1);
        strcpy(arguments[i],sep);
        i++;
    }
    arguments[i]=NULL;

    // 开始创建一个进程
    pid = fork();
    if(pid==0)
    {
//      puts("child into...");
        int len = strlen(param1);
        st = read(pipefd[0],buffer,len);
        if(st<0)
        {
            printf("read failure...\n");
            continue;
        }
        // 这里关掉子进程 的写入管道
        // 只让子进程读数据
        close(pipefd[1]);
//        usleep(100);
        // 进行exec 糸统调用
        execvp(buffer,arguments);
    }else if(pid>0)
    {
       // 关掉父进程从管道读取
       // 这样子父行成 管道实现 环形队列 这样实现了进程间通信
        close(pipefd[0]);
       // puts("parent into...");
        int len = strlen(param1);
        // 向管道端写入
        sst = write(pipefd[1],param1,len);    
        
        if(sst<0)
        {
            printf("write failure.....\n");
        }
      /**
 * 这里用wait 而不用usleep 
 * 一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,
 * 但PCB 还保留着,内核其中保存了一些信息,如果是正常终止则保存着退出状态,
 * 如果异常终止则保存着导致该进程终止的信号是哪个。这时候可以调用wait 获取
 * 这些信息,然后彻底清除掉这个进程。
 * 如果一个进程已经终止,但是它的父进程尚未调用wait or waitpid 对它进行清理,这时的进程装态称为
 * 僵尸zombie 进程。这里的wait 使父进程 阻塞 等待子进程终止,
 * ps u 查看到信息usleep 与 wait 两都的区别。。。
 * usleep 僵尸进程没有被清除。
 * wait 先让子进程 终止,也可以说去清理子进程
 *
 */
        //      usleep(100);
        wait(NULL);
/**
 * 父进程作清理工作。。
 * 释放内存。。
 */
        int i=0;
        for(;arguments[i]!=NULL;i++)
        {
          printf("arguments[%d] memory free!\n",i);
          free(arguments[i]);   
        }
    }else{
        perror("cannot fork!");
        exit(1);
    }
}
    return 0;
}


 
 
 

你可能感兴趣的:(linux编程)