Linux C 重定向和管道 学习

    xiaoxiao2021-03-25  70

    一. 重定向命令

    1. 在shell中运行命令时,系统为每个进程自动打开三个文件描述符。

    输入重定向 :more

    输出重定向: cat file>result.txt

    追加重定向: ls –l>>list.txt

    错误重定向 :./myfile 2>err.txt

    2. 重定向的实施者:从程序和执行的命令来看,重定向并不是由命令实现的,是由shell实现的,其 参数中并没有重定向符号和文件名,而且 重定向并不仅限于命令末尾。

    3. 实施重定向的3个条件:

    第一,标准I/O文件对应于最小的三个文件描述符

    第二,最低可用文件描述符原则 即:当打开文件时,为此文件安排的描述符总是可用的文件描述符中值最小的。

    第三,exec函数并不影响执行前打开的文件描述符集合。

    4. 实现重定向

    //重定向方法一: close then open

    #include <stdio.h> #include <stdlib.h> #include <fcntl.h> int main(int argc,char *argv[]){ int fd; char buf[80]; read(0,buf,80); write(1,buf,80); close(0); fd=open("./tmp.txt",O_RDONLY); if(fd != 0){ perror("open"); exit(1); } read(0,buf,80); write(1,buf,80); return 0; }

    //重定向方法二: open…close…dup…close

    dup函数: 功能:复制一个文件描述符

    定义:int dup ( int oldfd ); 参数:oldfd 表示将要复制的文件描述符 返回值:-1,出错; >-1,表示新的文件描述符 dup遵循最低文件描述符原则,新复制的文件描述符和oldfd共用一个文件表项。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(int argc,char *argv[]){ int fd,newfd; char buf[80]; read(0,buf,80); write(1,buf,80); fd=open("./tmp.txt",O_RDONLY); close(0); newfd = dup(fd); if(newfd != 0){ perror("dup"); exit(1); } close(fd); read(0,buf,80); write(1,buf,80); return 0; }

    //重定向方法三 : open … dup2 … close

    dup2 函数: 功能:复制一个文件描述符

    定义:int dup ( int oldfd , int newfd ); 参数:oldfd 表示将要复制的文件描述符,newfd 表示复制后得到的新的文件描述符 返回值:-1,出错; >-1,表示新的文件描述符

    dup2在复制文件描述符时,如果newfd对应有打开的文件,那么系统会先关闭newfd,然后再复制。

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(int argc,char *argv[]){ int fd,newfd; char buf[80]; read(0,buf,80); write(1,buf,80); fd=open("./tmp.txt",O_RDONLY); if(fd != -1){ perror("open"); exit(1); } newfd = dup2(fd,0); if(newfd != 0){ perror("dup2"); exit(1); } close(fd); read(0,buf,80); write(1,buf,80); return 0; }

    //重定向方法四: 使用popen实现重定向

    popen函数: 功能:建立一个指向进程的流

    定义:FILE *popen(char *cmd, char * mode); 参数:cmd 要执行的进程 mode 使用进程的方式 返回值: 非NULL 指向进程的流指针 NULL 失败 #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]){ FILE *fp; char buf[80]; int i=0; fp=popen("ls -l","r"); while(fgets(buf,80,fp) != NULL){ printf("%s\n",buf); } pclose(fp); return 0; }

    //示例: 实现 ls -l >list.txt

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(int argc,int *argv[]){ int pid,fd; printf("This is show how ro redirect ! \n"); if((pid = fork()) == -1){ //进程创建失败 perror("fork"); exit(1); } else if(pid == 0){ //子进程 close(1); fd = creat("list.txt",0644); if(execlp("ls","ls -l",NULL) < 0){ perror("exec"); exit(1); } } else{ //父进程 if(pid != 0){ wait(NULL); system("cat list.txt"); } } return 0; }

    二. 管道命令

    1 . 管道 cat /etc/passwd|grep root,类似于编写程序中的函数调用 grep(root, cat(“/etc/passwd”));

    管道命令将cat命令的输出作为grep命令的输入 管道命令可以更复杂: cat /etc/passwd|grep root|more 也可以和重定向一起使用 :cat /etc/passwd|grep root>result.txt

    2. 管道的基本特点:

    管道是特殊类型的文件,在满足先入先出的原则下可能进行读写,但不能定位读写位置 管道是单向的,要实现双向通信,需要使用两个管道 匿名管道可以实现具有亲缘关系的进程之间通信,命名管道可以实现在本机任意两个进程之间通信

    3. 使用管道的注意事项:

    (1)执行读操作时 如果管道中无数据,则读进程将被挂起直到数据被写进管道 如果所有写进程都关闭了管道的写端时,read返回0,意味着文件的结束。 当有多个进程对管道做读操作,需要有某种方法来协调这些读进程对管道的访问。 (2)执行写操作时 当管道已满时,写进程再对管道做写操作时,写进程会被阻塞 如果所有读进程关闭了管道的读端,再执行写操作时,写进程将会收到SIGPIPE信号, 若该信号不 能终止进程,则write调用返回-1,并将errno置为EPIPE 写入管道的数据大小,POSIX规定内核不会拆分小于512字节的块, 因此如果有两个进程向管道写数据,只要每一个进程都限制消息不大于512字节, 写入的消息就不会被内核拆分。 (3)管道分为匿名管道和命名管道

    4. 匿名管道:其内部实现隐藏在内核中,实质是一个以队列方式读写的内核缓冲区。

    匿名管道可以实现具有亲缘关系的进程之间的通信 (1)创建匿名管道: pipe函数: 功能:创建一条匿名管道 定义:int pipe ( int parr[2] ); 参数:parr 存放管道两端文件描述符的数组,parr[0]中存放管道的读端,parr[1]中存放的是管道的写端 返回值:-1,出错; 0 ,成功 (2)使用示例: #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc,char *argv[]){ int pfd[2]; char buf[80]; if(pipe(pfd) == -1){ perror("pipe"); exit(1); } printf("The pipe wil read from : %d , write to %d.\n",pfd[0],pfd[1]); write(pfd[1],"This is write to pipe!\n",23); read(pfd[0],buf,23); printf("%s",buf); return 0; }

    5. 命名管道: 无亲缘关系的进程间通信可以选择命名管道

    (1)创建命名管道:

    mkfifio函数:功能:创建一条命名管道

    定义:int mkfifo(char *filename, mode_t mode); 参数:filename 创建的FIFO文件名 mode 文件的权限模式 返回值:-1,出错; 0 ,成功

    (2)使用示例:

    #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc,char *argv[]){ int pid,fd; char buf[80]; mkfifo("fifotest",0644); if((pid = fork()) > 0){ fd=open("fifotest",O_WRONLY); write(fd,"Message to test FIFO!",22); close(fd); exit(0); } else if( pid == 0){ fd=open("fifotest",O_RDONLY); read(0,buf,80); printf("%s\n",buf); close(fd); exit(0); } else{# perror("fork"); exit(1); } return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-35805.html

    最新回复(0)