Shell实现(四) 执行命令的实现(包含管道的实现)
2015-10-24 23:03
525 查看
基本思路:
首先是执行命令的实现通过exec族函数实现的
然后是管道的实现,有两种实现方案,一种是调用pipe函数,但是既然可以自己写一个,为什么要记这么一个傻逼的函数呢?
调用pipe函数很无脑,需要一个规模为2的文件描述符数组,用来表示向管道中写的流和从管道中读的流
自己设计一个也很无脑,建立一个文件作为管道的载体,然后方法和上面的类似。
具体实现:
第一种方案是代码比较简单的自己实现的pipe的版本void run_shell ( ) { int i,j; fd[0] = open ( PIPE_FILE , O_CREAT|O_RDONLY , 0666 );//作为从管道中读出数据的端口 fd[1] = open ( PIPE_FILE , O_CREAT|O_WRONLY|O_TRUNC , 0666 );//作为向管道中写入数据的端口 for ( i = 0 ; i < cnt_group ; i++ )//遍历所有的命令组 { l = group[i].first; r = group[i].last; int pid = fork();//创建一个子线程执行命令 //fork会有两个返回值,在父线程中返回值为非0,子线程返回值为0 if ( pid == 0 ) run_command ( l , r-1 ); //执行指令(我采用的递归的方法实现) else waitpid ( 0 , NULL , 0 );//父线程阻塞,等待子线程执行完毕(不提供后台执行的解决方案) } }
然后是执行命令,想到管道的设计,一下子想到了递归,虽然迭代也很好实现,但是因为是在是懒,还是选择递归地写…
void run_command ( int l , int x ) { //printf ( "%d %d\n" , l , x ); pid_t pid; if ( x != l )//如果不是最后一条指令,那么继续创建新的进程 { pid = fork(); if ( pid==0 )//儿子进程跑前一条指令 run_command ( l , x-1 ); else waitpid ( 0 , NULL , 0 );//阻塞父亲进程等待儿子进程 } //printf ( "where am i %d\n" , x ); //根据管道重定向输入输出 if ( x != l ) dup2 ( fd[0] , fileno(stdin) ); if ( x != r-1 ) dup2 ( fd[1] , fileno(stdout) ); //执行命令 execvp ( cmd[x].cmd , cmd[x].param ); }
第二种方案是利用库中的pipe函数实现的方案
void run_shell ( ) { int pipe_fd[2]; int status; pipe(pipe_fd); pid_t child1,child2; if ((child1=fork())!=0)//父进程 { if ( (child2 = fork()) == 0 )//子进程 { close ( pipe_fd[1] ); close ( fileno ( stdin ) ); dup2 ( pipe_fd[0] , fileno(stdin)); close ( pipe_fd[0] ); execvp ( cmd[1].cmd , cmd[1].param ); } else { close ( pipe_fd[0]); close ( pipe_fd[1]); waitpid ( child2 , &status , 0 ); } waitpid ( child1 , &status , 0 ); } else { printf ( "subshell 3cmd %d\n" , getpid() ); close ( pipe_fd[0] ); close ( fileno(stdout)); dup2 ( pipe_fd[1] , fileno(stdout)); close ( pipe_fd[1] ); execvp ( cmd[0].cmd , cmd[0].param ); } }
贴心的小提示
需要用到的函数1.
int execvp(const char *file ,char * const argv []); //execvp()会从PATH 环境变量所指的目录中查找符合参数file 的文件名,找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。
2.
pid_t waitpid(pid_t pid,int * status,int options); //waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。
3.
#include<unistd.h> int pipe(int fd[2]) //函数传入值 fd[2]:管道的两个文件描述符,之后就是可以直接操作这两个文件描述符 //返回值 成功 0 失败 -1
4.
int dup2(int oldhandle,int newhandle); //复制文件句柄
5.
#include<fcntl.h> int open(constchar*pathname,intflags); int open(constchar*pathname,intflags,mode_tmode); //返回值:成功则返回文件描述符,否则返回-1
6.
close( int ) //关闭文件
相关文章推荐
- android wifi 无线调试
- 运维入门
- 动态清空 nohup 输出文件
- install scrapy with pip and easy_install
- Linux Shell常用技巧
- Shell 脚本编程陷阱
- shell字符串操作详解
- Shell中删除某些文件外所有文件的3个方法
- Ruby中执行Linux shell命令的六种方法详解
- VB使用shell函数打开外部exe程序的实现方法
- Shell编程的一些知识集合
- Shell中的for和while循环详细总结
- 什么是Shell?Shell脚本基础知识详细介绍
- Shell脚本中引用、调用另一个脚本文件的2种方法
- Shell脚本解压rpm软件包
- Linux Shell 数组建立及使用技巧
- Shell脚本实现复制文件到多台服务器的代码分享
- Shell脚本实现批量替换文件内容
- Shell脚本实现的一个简易Web服务器例子分享
- linux Shell学习笔记第五天