一. 重定向
重定向有输入重定向,输出重定向,追加重定向,以及错误重定向。
1.重定向命令:
输出重定向 cat file>result.txt
追加重定向 ls–l>>list.txt
错误重定向 ./myfile 2>err.txt
输入重定向 more
2.重定向在代码中的实现
- 实现重定向的三种方法
(1)close … open
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
main(){
int fd; char buf[80];
read(0,buf,80); write(1,buf,80);
close(0);
if((fd=open("/etc/passwd",O_RDONLY))!=0) {
perror("open"); exit(1);
}
read(0,buf,80); write(1,buf,80);
}
在代码中首先关闭了标准输入流,此时再打开一个文件时,采用描述符最小原则,所以此时的fd就等于0,也就是将标准输入重定向到了刚打开的文件中,此时的read就是从打开的文件中读取。
(2)open…close…dup…close
dup:复制一个文件描述符
main(){
int fd,newfd; char buf[80];
read(0,buf,80); write(1,buf,80);
fd=open("/etc/passwd",O_RDONLY);
close(0);
newfd=dup(fd);
if(newfd!=0){
perror("dup");
exit(1);
}
close(fd);
read(0,buf,80); write(1,buf,80);
}
在代码中首先代开文件,关闭了标准输入流,然后复制文件的描述符(复制的过程相当于重新打开fd所指向的文件,因为标准输入被关闭,所以此时的新文件描述符为0),然后关闭原来的文件描述符。所以此后的读取就是从打开的文件中读取。
(3)open…dup2…close
dup2:复制一个文件描述符
main(){
int fd,newfd;
char buf[80];
read(0,buf,80); write(1,buf,80);
fd=open("/etc/passwd",O_RDONLY);
newfd=dup2(fd,0);
if(newfd!=0){
perror("dup2"); exit(1);
}
close(fd);
read(0,buf,80); write(1,buf,80);
}
在代码中,首先打开文件,然后将标准输入文件描述符复制给刚才代开的文件描述符,此时标准输入被重定向到刚才打开的文件中,然后又关闭了刚才代开的文件描述符。此后的读取就是从文件中读取。
3.实现ls –l>list.txt(close then open)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
int main(void){
int pid,fd;
printf("This is to show how to redirect!\n");
if((pid=fork())==-1){
perror("fork");
exit(1);
}
else if(pid== 0){
close(1);
fd=open("list.txt",O_WRONLY|O_CREAT|O_APPEND,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)匿名管道用pipe()
创建,有名管道用mkfifo()
创建;
(2)匿名管道只能实现有亲缘关系的进程之间的通信,而有名管道可以实现无亲缘关系的进程间的通信;
1.使用匿名管道实现进程间通信:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
main(){
int pfd[2]; char buf[81];
pid_t pid;
if(pipe(pfd)==-1) {
perror("pipe");
exit(1);
}
printf("The pipe will read from %d, write to %d.\n", pfd[0], pfd[1]);
pid = fork();
if (pid == 0){
perror("fork");
exit(1);
}else if (pid == 0){
write(pfd[1],"This is write to pipe!\n",23);
}else{
read(pfd[0],buf,23);
printf("%s",buf);
wait(NULL);
}
exit(0);
}
对于匿名管道来说,管道的输入和输出是固定的,0代表输入端,1代表输出端,两者不可颠倒,否则会出错。
2.使用有名管道实现进程间通信
main() {
int pid,fd; char buf[80];
mkfifo("fifotest",0644); //创建有名管道,参数和open或creat函数相同
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(fd,buf,80);
printf("%s\n",buf);
close(fd); exit(0);
}
}
有名管道的使用方式和文件的方式是完全相同的,所以管道被叫做特殊的文件。