shell命令实现——bc计算器
2011-12-03 22:02
316 查看
我们将程序分为两个部分
1.主程序bcmain.c
1.主程序bcmain.c
#include "headall.h" /* * 实现bc程序:其主要功能是用来进行加减乘除的运算 * 其本质是一个客户端/服务器的模型 * * +---------+ pipe->dc +----------+ * stdin 0 >============> | * | bc | | dc | * stdout1 <============< | * +---------+ pipe<-dc +----------+ * * 用户首先会连接到bc并将bc连接到dc,调用dc程序后返回结果 * 该程序包括四个主要方面 * 1. bc与dc之间通过管道通信:由于管道是单向的,因此要建立两个管道。 * 2. 创建一个新的进程来运行dc * 3. 在新进程中,由于我们要execlp shell的dc程序,dc程序的输入是标准输入, * dc程序的输出是标准输出,而我们希望重定向这两个到管道 * * 4. 在父进程中,我们会读取用户的输入,进行解析,将命令通过管道传给dc * dc进行读取数据,返回结果给bc,bc显示给用户 * * 3 4 5 6 * | | | | * | | | | * | | | | * +———+ +--+ * */ int main(){ int pid; // two pipe int todc[2],fromdc[2]; // make two pipes if( pipe(todc) == -1 || pipe(fromdc) == -1) oops("pipe failed",1); //printf("todc = %d,%d\n",todc[0],todc[1]); //printf("todc = %d,%d\n",fromdc[0],fromdc[1]); pid = fork(); switch(pid){ case -1: oops("fork failed",1);break; // in child process case 0: dc_deal(todc,fromdc); break; // parent process default: bc_deal(todc,fromdc); } }2.处理程序proclib.c
#include "headall.h" int dc_deal(int *,int *); int bc_deal(int *,int *); /* * review 匿名管道 * pipe(array[2]); * 创建一个管道,并为这个数组的两个元素创建文件描述符 * 这里要注意: * array[0] 是从管道中读取数据 * array[1] 是向管道中写数据 * */ //父进程的处理函数 int bc_deal(int *todc,int *fromdc){ char message[BUFSIZ],operation[BUFSIZ]; int num1,num2; // 管道1,写入dc的管道 // 父子进程共享管道 // 在父进程方面关闭 todc[0],关闭读管道 close(todc[0]); // 管道2:读取dc的管道 // 在父进程方面关闭 fromdc[1],关闭写管道 close(fromdc[1]); FILE *fpout,*fpin; // 转换文件描述符为文件流 fpout = fdopen(todc[1],"w"); fpin = fdopen(fromdc[0],"r"); if(fpout == NULL || fpin == NULL) oops("error to convert the pipes to streams",1); while(printf("our bc:"),fgets(message,BUFSIZ,stdin)!=NULL){ // 这里有兴趣的可以查一下sscanf的用途 // 此函数很强大 // %[- +]表示操作符号,这里一定要注意 // -号不能放在中间,否则会被当做 [A-Z]中的符号而无效的 // 如果放中间会让减法没有用。 if(sscanf(message,"%d%[- + * / ^]%d", &num1,operation,&num2)!=3){ //printf("op = %c\n",operation); //printf("num1 = %d,num2 = %d\n",num1,num2); printf("syntax error\n"); continue; } //printf("op = %c\n",operation); //printf("num1 = %d,num2 = %d\n",num1,num2); if(fprintf(fpout,"%d\n %d\n %c\np\n",num1,num2, *operation)==EOF) oops("error writing",1); fflush(fpout); if(fgets(message,BUFSIZ,fpin)==NULL) break; printf("%d %c %d = %s",num1,*operation,num2,message); } fclose(fpout); fclose(fpin); } // 子进程的处理函数 int dc_deal(int todc[2],int fromdc[2]){ // printf("todc[2]= %d,%d\n",todc[0],todc[1]); // printf("fromdc[2]= %d,%d\n",fromdc[0],fromdc[1]); // 管道1,写入dc的管道 // 父子进程共享管道 // 在子进程方面关闭 todc[1],关闭写管道 close(todc[1]); // 管道2:读取dc的管道 // 在子进程方面关闭 fromdc[0],关闭读管道 close(fromdc[0]); // printf("todc[2]= %d,%d\n",todc[0],todc[1]); // printf("fromdc[2]= %d,%d\n",fromdc[0],fromdc[1]); // 子进程方面此时拥有的是: // 与管道1相关的是,读管道的 todc[0] // 与管道2相关的是,写管道的 fromdc[1] // 我们需要在该子进程中执行dc, // dc程序的数据来源是标准输入,结果会输出到标准输出 // 因此我们要对该程序进行重定向 // 读管道 todc[0]作为数据来源定向到标准输入 if(dup2(todc[0],0)==-1) oops("dup2 failed",1); // todc[0]完成使命 close(todc[0]); //printf("after dup2 0,0\n"); //printf("todc[2]= %d,%d\n",todc[0],todc[1]); //printf("fromdc[2]= %d,%d\n",fromdc[0],fromdc[1]); // 写管道 fromdc[1]作为数据的输出定向到标准输出 if(dup2(fromdc[1],1) == -1) oops("dup2 failed",1); // fromdc[1]关闭即可 close(fromdc[1]); //printf("after dup2 1,1\n"); //printf("todc[2]= %d,%d\n",todc[0],todc[1]); //printf("fromdc[2]= %d,%d\n",fromdc[0],fromdc[1]); // 我们可以干正事了 execlp("dc","dc",NULL); oops("dc failed",5); }
相关文章推荐
- 关于shell 命令在七牛的使用小技巧 使用七牛的curl 实现表单上传
- shell脚本传参实现scp命令无需输入密码和别的参数
- Java实现ssh连接linux并执行shell命令
- curl 命令,curl监控网页shell脚本,curl多进程实现并控制进程数
- linux实现shell命令支持ipv4地址转换
- 模拟shell实现su命令(切换用户)
- cd命令为何要实现成shell内建命令
- 解析如何在C语言中调用shell命令的实现方法
- Linux(7) 常用命令扩展 改变用户环境变量 (可以实现登陆就执行shell脚本)
- shell实现ftp命令示例
- MongoDB_03之使用shell命令实现对文档数据的操作
- 完美实现GIF动画缩略图(GIF压缩使用C++、shell命令、php)
- UNIX管道应用及Shell实现(二)-命令解析
- Shell脚本中使用for循环和cat命令实现按顺序合并文件
- Java实现远程联接服务器执行shell命令
- 最近才知道的一款软件,可以实现在windows下使用linux下的命令,甚至可以使用简单的shell
- Windows使用SSH Secure Shell实现免密码登录Linux的方法以及使用scp2命令免密码下载文件
- shell通过scp命令实现简单数据推送
- shell编程笔记六:实现ll命令
- shell练习:写一个脚本实现如下功能:输入一个数字,然后运行对应的一个命令。显示命令如下:*cmd