输入输出重定向和管道是进程间的一种特殊方式。
Unix进程使用标准的文件描述符,0(stdin)、1(stdout)、2(stderr),当进程请求一个新的文件描述符的时候,系统内核将最低可用的文件描述符给它。通常情况下这三个文件描述符是打开着的。
一、I/O重定向
在Linux中,我们通过shell与系统交互,本质上就是建立进程,在进程中执行操作。 一般的输入是stdin,标准输入键盘。输出为终端界面。可以利用重定向将标准输入或输出设为传统意义文件(因为在Linux下一切皆为文件)
关于文件描述符:Unix进程使用文件描述符0、1、2作为标准输入、输出和错误的通道。其次,当进程请求一个新的文件描述符的时候,系统内核将
最低可用的文件描述符给它。
I/O重定向用到的函数有dup和dup2()
函数原型:
#include <unistd.h>
newfd = dup(oldfd);
或
newfd = dup2(oldfd,newfd); //一般来将先关闭掉newfd,然后复制oldfd都newfd位置
常用操作
1.close-then open
2.open-close-dup-close
example:
/*close-then-open
*
*
*/
#include <stdio.h>
#include <fcntl.h>
int main()
{
int fd;
char line[100];
/*read and input two lines*/
fgets(line,100,stdin); printf("%s\n",line);
fgets(line,100,stdin); printf("%s\n",line);
close(0); /*关闭标准输入,接着创建的文件描述符自动匹配到标准输入位置上*/
fd = open("/etc/passwd",O_RDONLY);
if(fd == -1)
{
perror("open");
exit(1);
}
wait(NULL);
fgets(line,100,stdin); printf("%s\n",line);
fgets(line,100,stdin); printf("%s\n",line);
return 0;
}
二、管道
原型:
#include<unistd.h>
result = pipe(int array[2]);
example:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFSIZ 10
int main()
{
int len, i, apipe[2];
char buf[BUFSIZ];
char buf2[BUFSIZ];
if(pipe(apipe) == -1){
perror("pipe");
exit(1);
}
printf("got a file descriptor %d,%d \n",apipe[0],apipe[1]);
fgets(buf,BUFSIZ,stdin);
len = strlen(buf);
write(apipe[1],buf,len);
printf("pipe exit:\n");
read(apipe[0],buf2,len);
printf("%s\n",buf2);
}
管道可以应用于进程中,通过子进程写,父进程读
#include<stdio.h>
#include <unistd.h>
int main()
{
int fd;
int pipefd[2];
fd = fork();
pipe(pipefd);
if(fd == -1)
perror();
else if(pid == 0)
//write(pipe[1],buf,len); 从buf写到管道
else
//read(pipe[0],buf,len); 读buf到管道
return 0;
}
三、fdopen和popen使用
fdopen使得对远端的进程的处理就像处理常规文件一样。popen函数,通过封装pipe、fork、dup、exex等系统调用使得对程序和文件的操作手法一样。
下面以一下简易计算器示例说明fdopen使用,结合了管道
#include <stdio.h>
#include <stdlib.h>
#define oops(x,m) {perror(x);exit(m);}
void be_dc(int in[2],int out[2]);
void be_bc(int todc[],int fromdc[]);
void fatal(char*[]);
int main()
{
<span style="white-space:pre"> </span>int pid, todc[2],fromdc[2];
<span style="white-space:pre"> </span>if(pipe(todc) == -1 || pipe(fromdc) == -1)
<span style="white-space:pre"> </span>oops("pipe failed",1);
<span style="white-space:pre"> </span>if((pid = fork()) == -1)
<span style="white-space:pre"> </span>oops("fork failed",2);
<span style="white-space:pre"> </span>if(pid == 0) /*child is dc*/
<span style="white-space:pre"> </span>be_dc(todc,fromdc);
<span style="white-space:pre"> </span> else{ /*parent is ui*/
<span style="white-space:pre"> </span> be_bc(todc,fromdc);
<span style="white-space:pre"> </span>wait(NULL);
<span style="white-space:pre"> </span>}
}
void be_dc(int in[2],int out[2])
/*
*set up stdin and stdout,then execl dc
*/
{
<span style="white-space:pre"> </span>if(dup2(in[0],0) == -1){
<span style="white-space:pre"> </span>oops("can not dup",1);
}
<span style="white-space:pre"> </span>close(in[0]);
<span style="white-space:pre"> </span>close(in[1]); /*won't use*/
<span style="white-space:pre"> </span>if (dup(out[1],1) == -1){
<span style="white-space:pre"> </span> oops("can not dup",2);
}
<span style="white-space:pre"> </span>close(out[1]);
<span style="white-space:pre"> </span>close(out[0]);/*won't use*/
if(execlp("dc","dc","-",NULL) == -1)
<span style="white-space:pre"> </span>oops("can not run dc\n",3);
}
void be_bc(int todc[2],int fromdc[2])
{
<span style="white-space:pre"> </span>int num1,num2;
<span style="white-space:pre"> </span>char operation[BUFSIZ],message[BUFSIZ],*fgets();
<span style="white-space:pre"> </span>FILE *fpout,*fpin,*fpopen;
<span style="white-space:pre"> </span>close(todc[0]); /*won'r read,use todc[1] to write*/
<span style="white-space:pre"> </span>close(fromdc[1]);/*won't write,use fromdc[0] to read*/
<span style="white-space:pre"> </span>fpout = fdopen(todc[1],"w");
<span style="white-space:pre"> </span>fpin = fdopen(fromdc[0],"r");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(fpout == NULL || fpin == NULL)
<span style="white-space:pre"> </span> fatal("Error converting pipes to streams!\n");
<span style="white-space:pre"> </span>while(printf("tiny:"),fgets(message,BUFSIZ,stdin) != NULL){
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>if(sscanf(message,"%d %[- + * / ^] %d",&num1,operation,&num2) != 3){
<span style="white-space:pre"> </span> printf("sytax error!\n");
<span style="white-space:pre"> </span> continue;
}
<span style="white-space:pre"> </span> if(fprintf(fpout,"%d\n%d\n%c\np\n",num1,num2,*operation) == EOF){
<span style="white-space:pre"> </span> fatal("error writting!\n"); /*use p to print the result*/
}
<span style="white-space:pre"> </span>fflush(fpout);
<span style="white-space:pre"> </span>if(fgets(message,BUFSIZ,fpin) == NULL)
<span style="white-space:pre"> </span> break;
<span style="white-space:pre"> </span> printf("%d %s %d = %s",num1,operation,num2,message);
}
<span style="white-space:pre"> </span>fclose(todc[1]);
<span style="white-space:pre"> </span>fclose(fromdc[0]);
}
void fatal(char* mess[])
{
<span style="white-space:pre"> </span>fprintf(stderr,"Error:%s\n",mess);
<span style="white-space:pre"> </span>exit(1);
}
popen使用
FILE* fp;
fp = popen("ls","r");
fgets(buf,len,fp);
pclose(fp);
示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
<span style="white-space:pre"> </span>FILE* fp;
<span style="white-space:pre"> </span>char buf[100];
<span style="white-space:pre"> </span>int i = 0;
<span style="white-space:pre"> </span>fp = popen("who | sort","r");
<span style="white-space:pre"> </span>while(fgets(buf,100,fp) != NULL){
<span style="white-space:pre"> </span><span style="white-space:pre"> </span>printf(" %3d %s\n",i++,buf);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>return 0;
}