linux多重管道的实现,Linux——实现简单的交互式shell

实现简单的交互式shellshell

使用已学习的各类C函数实现一个简单的交互式Shell,要求:函数

一、给出提示符,让用户输入一行命令,识别程序名和参数并调用适当的exec函数执行程序,待执行完成后再次给出提示符。学习

二、该程序可识别和处理如下符号:设计

1) 简单的标准输入输出重定向:仿照例 “父子进程ls| wc -l”,先dup2而后exec。code

2) 管道(|):Shell进程先调用pipe建立管道,而后fork出两个子进程。一个子进程关闭读端,调用dup2将写端赋给标准输出,另外一个子进程关闭写端,调用dup2把读端赋给标准输入,两个子进程分别调用exec执行程序,而Shell进程把管道的两端都关闭,调用wait等待两个子进程终止。相似于“兄弟进程间ls| wc –l”练习的实现。进程

你的程序应该能够处理如下命令:ip

○ls△-l△-R○>○file1○字符串

○cat○○file1○get

注:○表示零个或多个空格,△表示一个或多个空格cmd

实现步骤:

1. 接收用户输入命令字符串,拆分命令及参数存储。(自行设计数据存储结构)

2. 实现普通命令加载功能

3.实现输入、输出重定向的功能

4.实现管道

5.支持多重管道

实现上述功能的源码以下:

#include

#include

#include

#include

#include

#include

#define MAXLINE 4096

#define MAXPIPE 16

#define MAXARG 8

struct {

char *argv[MAXARG];

char *in, *out;

} cmd[MAXPIPE+1];

int parse(char *buf, int cmdnum)

{

int n = 0;

char *p = buf;

cmd[cmdnum].in = cmd[cmdnum].out = NULL;

//ls -l -d -a -F > out

while (*p != '\0') {

if (*p == ' ') { //将字符串中全部的空格,替换成'\0',方便后续拆分字符串

*p++ = '\0';

continue;

}

if (*p == '

*p = '\0';

while (*(++p) == ' '); /* cat < file 处理连续多个空格的状况*/

cmd[cmdnum].in = p;

if (*p++ == '\0')//输入重定向

return -1;

continue;

}

if (*p == '>') {

*p = '\0';

while (*(++p) == ' ');

cmd[cmdnum].out = p;

if (*p++ == '\0')

return -1;

continue;

}

if (*p != ' ' && ((p == buf) || *(p-1) == '\0')) {

if (n < MAXARG - 1) {

cmd[cmdnum].argv[n++] = p++; //"ls -l -R > file"

continue;

} else {

return -1;

}

}

p++;

}

if (n == 0) {

return -1;

}

cmd[cmdnum].argv[n] = NULL;

return 0;

}

int main(void)

{

char buf[MAXLINE];

pid_t pid;

int fd, i, j, pfd[MAXPIPE][2], pipe_num, cmd_num;

char* curcmd, *nextcmd;

while (1) {

printf("mysh%% ");

if (!fgets(buf, MAXLINE, stdin))

exit(0);

// "ls -l\n"

if (buf[strlen(buf)-1]=='\n')

buf[strlen(buf)-1]='\0';

cmd_num = 0;

nextcmd = buf;

while ((curcmd = strsep(&nextcmd, "|"))) {

if (parse(curcmd, cmd_num++)<0) {

cmd_num--;

break;

}

if (cmd_num == MAXPIPE + 1)

break;

}

if (!cmd_num)

continue;

pipe_num = cmd_num - 1; //根据命令数肯定要建立的管道数目

for (i = 0; i < pipe_num; i++) { //建立管道

if (pipe(pfd[i])) {

perror("pipe");

exit(1);

}

}

for (i = 0; i < cmd_num; i++) { //管道数目决定建立子进程个数

if ((pid = fork()) == 0)

break;

}

if (pid == 0) {

if (pipe_num) { //用户输入的命令中含有管道

if (i == 0) { //第一个建立的子进程

dup2(pfd[0][1], STDOUT_FILENO);

close(pfd[0][0]);

for (j = 1; j < pipe_num; j++) { //在该子进程执行期间,关闭该进程使用不到的其余管道的读端和写端

close(pfd[j][0]);

close(pfd[j][1]);

}

} else if (i==pipe_num) { //最后一个建立的子进程

dup2(pfd[i-1][0], STDIN_FILENO);

close(pfd[i-1][1]);

for (j = 0; j < pipe_num-1; j++) { //在该子进程执行期间,关闭该进程不使用的其余管道的读/写端

close(pfd[j][0]);

close(pfd[j][1]);

}

} else {

dup2(pfd[i-1][0], STDIN_FILENO); //重定中间进程的标准输入至管道读端

close(pfd[i-1][1]); //close管道写端

dup2(pfd[i][1], STDOUT_FILENO); //重定中间进程的标准输出至管道写端

close(pfd[i][0]); //close管道读端

for (j = 0; j < pipe_num; j++) //关闭不使用的管道读写两端

if (j != i || j != i-1) {

close(pfd[j][0]);

close(pfd[j][1]);

}

}

}

if (cmd[i].in) { /*用户在命令中使用了输入重定向*/

fd = open(cmd[i].in, O_RDONLY); //打开用户指定的重定向文件,只读便可

if (fd != -1)

dup2(fd, STDIN_FILENO); //将标准输入重定向给该文件

}

if (cmd[i].out) { /*用户在命令中使用了输出重定向*/

fd = open(cmd[i].out, O_WRONLY|O_CREAT|O_TRUNC, 0644); //使用写权限打开用户指定的重定向文件

if (fd != -1)

dup2(fd, STDOUT_FILENO); //将标准输出重定向给该文件

}

execvp(cmd[i].argv[0], cmd[i].argv); //执行用户输入的命令

fprintf(stderr, "executing %s error.\n", cmd[i].argv[0]);

exit(127);

}

/* parent */

for (i = 0; i < pipe_num; i++) { /*父进程不参与命令执行,关闭其掌握的管道两端*/

close(pfd[i][0]);

close(pfd[i][1]);

}

for (i = 0; i < cmd_num; i++) { /*循环回首子进程*/

wait(NULL);

}

}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值