版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013139008/article/details/79432139
#include "ourhdir.h"
#include <sys/wait.h> // waitpid
#include <sys/types.h> // pid_t
#define DFL_PAGER "/usr/bin/more" // 默认的分页命令
int main(int argc, char *argv[]) {
int fd[2]; // 使用全双工管道,父进程写入写端,子进程读取读端
int n; // 父进程读取文件的字符数
char line[MAXLINE]; // MAXLINE=4096, ourhdir.h中定义
char *pager; // 从环境变量中获取分页命令的指针
char *argv0; // 调用exec函数使用的指针
FILE *fp;
pid_t pid;
// 从命令行中获得待读取的文件
if (argc != 2) {
err_quit("usage: a.out <filename>");
}
// 打开输入的文件
if ((fp = fopen(argv[1], "r")) == NULL) {
err_sys("fopen %s error", argv[1]);
}
// 创建管道
if (pipe(fd) < 0) {
err_sys("pipe error");
}
// 创建子进程
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid > 0) {
close(fd[0]); // 关闭读端,管道返回的是文件描述符,所以使用close
while (fgets(line, MAXLINE, fp) != NULL) {
n = strlen(line);
if (write(fd[1], line, n) < n) {
err_sys("write error to pipe");
}
}
// 如果是fgets函数出错退出,则打印出错信息
if (ferror(fp)) {
err_sys("fget error");
}
// 写端使用完之后,关闭
close(fd[1]);
// 等待子进程退出
if (waitpid(pid, NULL, 0) < 0) {
err_sys("waitpid error");
}
} else {
close(fd[1]); // 子进程关闭写端
// 将读端重定向到标准出错
// 首先判断读端是否就是标准出错。如果不判断,而且读端已经是标准出错
// 即使重定向执行成功,因为执行了close函数,就会把标准出错关闭掉
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
err_sys("dup2 error to stdin");
}
close(fd[0]);
}
// 获得环境变量:分页执行程序,获得失败,使用默认指定
// 默认分页命令字符串:/usr/bin/more
// 获得的环境变量分页命令:/usr/bin/more 或 more
if ((pager = getenv("PAGER")) == NULL) {
pager = DFL_PAGER;
}
// strrchr:返回字符串中从最后一个字符开始的指定字符的指针
// 若未出现指定字符返回NULL
// pager指向:/usr/bin/more
if ((argv0 = strrchr(pager, '/')) != NULL) {
argv0++;
// pager指向:more
} else {
argv0 = pager;
} // 该代码段执行结束,argv0指向的字符串是:more
// 为什么执行了more命令就是将标准输出分页输出了?
// 标准输出会作为more的输入进行分页显示?
if (execl(pager, argv0, (char *)0) < 0) {
err_sys("execl error for %s", pager);
}
}
return 0;
}