C语言父子进程shell命令重定向到管道传递(双管道)

/**
*在管道一端循环写入shell命令,并将数据重定向
*到管道中,在另一端接收管道中数据
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#define SIZE 128				//缓存区大小	

void read_from_pipe(int fd[],int err_fd[]);	//从管道读数据
void write_to_pipe(int fd[],int err_fd[]);	//向管道写数据
void handle(int signo);			//信号处理函数
int main()
{
	int fd[2];//文件描述符数组,数据管道,传输shell命令执行返回的结果
	int err_fd[2];//文件描述符数组,错误管道,传输shell命令执行产生的错误信息
	int ret;
	int err_ret;
	pid_t pid;
	char s[3];
	do
	{
		ret=pipe(fd);//创建无名管道fd[0]读端,fd[1]写端
		if(ret!=0)
		{
			perror("pipe error");
			exit(1);
		}
		err_ret=pipe(err_fd);
		if(err_ret!=0)
		{
			perror("pipe error");
			exit(1);
		}
		signal(SIGCHLD,handle);//子进程退出信号捕捉函数
		pid=fork();//创建进程
		if(pid==0)//子进程
		{	
			write_to_pipe(fd,err_fd);	
			exit(1);
		}
		else if(pid>0)//父进程
		{	
			wait();
			read_from_pipe(fd,err_fd);
		}
		else
		{
			perror("fork error");
			exit(1);
		}
		printf("<y or n>--->");
		fgets(s,3,stdin);
	}while(strcmp("y\n",s)==0);
	return 0;
}
void read_from_pipe(int fd[],int err_fd[])
{
	char buf_read[SIZE];
	memset(buf_read,'\0',SIZE);
	char buf_err[SIZE];
	memset(buf_err,'\0',SIZE);
	close(fd[1]);
	close(err_fd[1]);
	if(read(fd[0],buf_read,SIZE)>=0 && read(err_fd[0],buf_err,SIZE)==0)
	{
		printf("命令正确\n");
		if(strlen(buf_read)==0)
		{
			printf("此操作没有数据可写\n");
		}
		else
		{
			printf("data:\n");
			printf("%s",buf_read);
		}
		printf("=========================\n");
	}
	else
	{	
		printf("命令错误\n");	
		printf("error info:\n");
		printf("%s",buf_err);
		printf("=========================\n");
	}
	close(fd[0]);
	close(err_fd[0]);
}
void write_to_pipe(int fd[],int err_fd[])
{
	char buf_write[SIZE];
	int len;int ret;
	memset(buf_write,'\0',SIZE);//分配内存空间
	close(fd[0]);//关闭数据管道读端
	close(err_fd[0]);//关闭错误管道读端
	printf("input:");
	fflush(stdout);//缓存清空(注意!!!)
	dup2(fd[1],1);//标准输出重定向到数据管道写端
	dup2(err_fd[1],2);//标准错误重定向到错误管道写端
	fgets(buf_write,SIZE,stdin);
	len=strlen(buf_write);
	buf_write[len-1]='\0';
	ret=execlp("sh","sh","-c",buf_write,NULL);//执行shell命令
	if(ret==-1)
	{
		perror("execlp error");
		exit(1);
	}
	close(fd[1]);
	close(err_fd[1]);
}
void handle(int signo)
{
	if(signo==SIGCHLD)
	printf("子进程退出\n");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Linux 中,使用 C 语言模拟 shell 命令可以通过调用系统函数实现。以下是一个简单的例子,演示了如何使用 C 语言实现重定向管道通信。 首先,我们需要包含一些头文件: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> ``` 接下来,我们可以定义一些常量,例如: ```c #define MAX_ARGS 10 #define MAX_BUFFER 1024 ``` 然后,我们可以定义一个函数来解析用户输入的命令,并将其分解为单个参数。以下是一个简单的实现: ```c void parse_command(char *command, char **args, int *redirect_input, int *redirect_output) { int arg_count = 0; char *token; char *rest = command; while ((token = strtok_r(rest, " ", &rest))) { if (*token == '<') { *redirect_input = open(token + 1, O_RDONLY); } else if (*token == '>') { *redirect_output = open(token + 1, O_WRONLY | O_CREAT | O_TRUNC, 0644); } else { args[arg_count++] = token; } } args[arg_count] = NULL; } ``` 此函数通过使用 `strtok_r()` 函数将命令分解为参数。如果命令包含输入重定向符 `<`,则将 `redirect_input` 指针设置为打开输入文件的文件描述符。如果命令包含输出重定向符 `>`,则将 `redirect_output` 指针设置为打开输出文件的文件描述符。在解析完成后,参数将存储在 `args` 数组中。 接下来,我们可以定义一个函数来处理管道通信。以下是一个简单的实现: ```c void pipe_commands(char **commands) { int fd[2]; pid_t pid1, pid2; char *args1[MAX_ARGS], *args2[MAX_ARGS]; if (pipe(fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } parse_command(commands[0], args1, NULL, &fd[1]); parse_command(commands[1], args2, &fd[0], NULL); pid1 = fork(); if (pid1 == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid1 == 0) { close(fd[0]); dup2(fd[1], STDOUT_FILENO); close(fd[1]); execvp(args1[0], args1); } else { pid2 = fork(); if (pid2 == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid2 == 0) { close(fd[1]); dup2(fd[0], STDIN_FILENO); close(fd[0]); execvp(args2[0], args2); } else { close(fd[0]); close(fd[1]); wait(NULL); wait(NULL); } } } ``` 此函数创建一个管道,然后使用 `parse_command()` 函数解析两个命令,并将其分别存储在 `args1` 和 `args2` 数组中。接下来,它调用 `fork()` 函数创建两个子进程,其中一个子进程执行第一个命令,另一个子进程执行第二个命令。使用 `dup2()` 函数将子进程的标准输出或标准输入连接到管道的适当端口。最后,主进程等待两个子进程完成。 最后,我们可以定义一个主函数来使用这些函数来执行用户输入的命令。以下是一个简单的实现: ```c int main() { char buffer[MAX_BUFFER]; char *commands[2]; int redirect_input = 0, redirect_output = 0; while (1) { printf("$ "); if (fgets(buffer, MAX_BUFFER, stdin) == NULL) break; commands[0] = strtok(buffer, "|"); if ((commands[1] = strtok(NULL, "\n")) != NULL) { pipe_commands(commands); } else { parse_command(commands[0], commands, &redirect_input, &redirect_output); pid_t pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { if (redirect_input) { dup2(redirect_input, STDIN_FILENO); close(redirect_input); } if (redirect_output) { dup2(redirect_output, STDOUT_FILENO); close(redirect_output); } execvp(commands[0], commands); } else { wait(NULL); } } } return 0; } ``` 此函数使用 `fgets()` 函数从标准输入读取用户输入的命令。如果命令包含管道符 `|`,则使用 `strtok()` 函数将命令分解为两个命令,并使用 `pipe_commands()` 函数执行它们之间的管道通信。否则,就使用 `parse_command()` 函数解析命令,并使用 `fork()` 函数创建子进程来执行命令。在子进程中,使用 `dup2()` 函数将标准输入或标准输出重定向到适当的文件描述符。最后,主进程使用 `wait()` 函数等待子进程完成。 这就是使用 C 语言模拟 shell 命令的基本方法。请注意,此实现仅用于演示目的,并且可能需要进行更改以处理更多情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值