linux系统编程综合练习-实现一个小型的shell程序(四)
#include "execute.h" #include "def.h" #include "externs.h" #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <linux/limits.h> #include <fcntl.h> void forkexec(int i){ pid_t pid; pid = fork(); if(pid == -1) { /* 创建进程失败了 */ ERR_EXIT("fork"); } if(pid > 0) { /* 父进程 */ if (backgnd == 1) printf("%d\n", pid); lastpid = pid; } else if(pid == 0) { /* 子进程 */ /* 表示将第一条简单命令的infd重定向至/dev/null,其中cmd[i].infd == 0只有可能是第一条简单命令 */ /* 当第一条命令试图从标准输入获取数据的时候立既返回EOF */ if(cmd[i].infd == 0 && backgnd == 1){ //屏蔽后台作业,因为没有实现作业控制 cmd[i].infd = open("/dev/null", O_RDONLY); } /* 将第一个简单命令进程作为进程组组长 */ if(i == 0){ setpgid(0, 0); } if(cmd[i].infd != 0){ //说明该命令的输入是指向管道的读端 close(0); dup(cmd[i].infd); } if(cmd[i].outfd != 1){ //说明该命令的输出指向的是管道的写端 close(1); dup(cmd[i].outfd); } /* 关闭3以上的所有文件描述符 */ /*int i; for(i=3; i<OPEN_MAX; ++i){ close(i); }*/ /*前台作业能够接收SIGINT,SIGQUIT信号,这两个信号就要恢复成默认操作*/ if(backgnd == 0){//非后台作业 signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); } /* 开始替换进程 */ execvp(cmd[i].args[0], cmd[i].args); /* 如果执行到这句,则证明替换失败了 */ exit(EXIT_FAILURE); } } int execute_disk_command(void){ /* ls | grep init | wc -w */ if(cmd_count == 0) { return 0; } if(infile[0] != ‘\0‘){ cmd[0].infd = open(infile, O_RDONLY); } if(outfile[0] != ‘\0‘){ if(append)//说明是以追加的方式 cmd[cmd_count-1].outfd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0666); else cmd[cmd_count-1].outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); } /* 因为后台作业不会调用wait等待子进程退出,为避免僵尸进程,可以忽略SIGCHLD信号 */ if(backgnd == 1){ signal(SIGCHLD, SIG_IGN); }else{ signal(SIGCHLD, SIG_DFL); } int i; /* 管道描述符 */ int fds[2]; int fd; for(i=0; i<cmd_count; ++i){ /* 如果不是最后一条命令,则需要创建管道 */ if(i < cmd_count-1){ pipe(fds); /* 第一条命令的输出不再是标准输出,而是管道的写端 */ cmd[i].outfd = fds[1]; /* 第二条命令的输入不再是标准输入,而是管道的读端 */ cmd[i+1].infd = fds[0]; } /* 创建一个进程,并且替换成系统命令 */ forkexec(i); if((fd = cmd[i].infd) != 0) close(fd); if((fd = cmd[i].outfd) != 1) close(fd); } if(backgnd == 0){//如果是非后台作业 while(wait(NULL) != lastpid) ; } }
将其forkexec函数也抽取到execute.c文件中,下面来进行编译一下:
另外在编译成,需要修改一下Makefile:
#include "builtin.h" #include "parse.h" #include "externs.h" #include <stdlib.h> #include <stdio.h> typedef void (*CMD_HANDLER)(void); typedef struct builtin_cmd { char *name; CMD_HANDLER handler; } BUILTIN_CMD; void do_exit(void); void do_cd(void); void do_type(void); BUILTIN_CMD builtins[] = { {"exit", do_exit}, {"cd", do_cd}, {"type", do_type}, {NULL, NULL} }; /* * 内部命令解析 * 返回1表示为内部命令,0表示不是内部命令 */ int builtin(void) { /* if (check("exit")) do_exit(); else if (check("cd")) do_cd(); else return 0; return 1; */ int i = 0; int found = 0; while (builtins[i].name != NULL) { if (check(builtins[i].name)) { builtins[i].handler(); found = 1; break; } i++; } return found; } void do_exit(void) { printf("exit\n"); exit(EXIT_SUCCESS); } void do_cd(void) { printf("do_cd ... \n"); } void do_type(void) { printf("do_type ... \n"); }
编译运行:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。