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

    xiaoxiao2025-09-18  71

    /**  * @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 <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h>

    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; }

         
    转载请注明原文地址: https://ju.6miu.com/read-1302800.html
    最新回复(0)