在C语言子进程中通过pipe系统调用处理cat命令输入的操作系统问题求助
解决fork/pipe配合cat命令实现输入字符串转换的问题
你的代码核心问题分析
我看了你的代码,现在有几个关键错误导致无法正常工作:
execvp之后的代码永远不会执行:一旦execvp("cat", ...)成功调用,子进程的整个地址空间会被cat程序替换,所以你写在execvp后面的write等代码完全不会运行,这是最致命的问题。dup2的调用方向完全搞反:dup2(new_fd, old_fd)的作用是把new_fd的内容复制到old_fd,让old_fd指向new_fd的文件。比如你想让cat的输出写到管道,应该是dup2(fd2[1], STDOUT_FILENO),而不是反过来。- 管道关闭逻辑错误:没有及时关闭不需要的管道端,会导致进程阻塞在
read/write操作上。 - 缺少字符串转换逻辑:你还没实现把输入的
dog替换成fish的核心逻辑。
修正后的代码实现
下面是调整后的代码,实现了:父进程创建管道,子进程执行cat并将输出写入管道;父进程从管道读取cat的输出,把其中的dog替换成fish,然后输出原内容+转换后的内容(符合你预期的dog fish dog fish效果):
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<string.h> #include<sys/wait.h> // 字符串替换函数:把str中的old_str替换成new_str void replace_string(char *str, const char *old_str, const char *new_str) { char buffer[1024] = {0}; char *pos = strstr(str, old_str); if (!pos) return; // 没找到就直接返回 // 复制替换前的部分 strncpy(buffer, str, pos - str); // 拼接新字符串 strcat(buffer, new_str); // 拼接替换后的剩余部分 strcat(buffer, pos + strlen(old_str)); // 把结果复制回原字符串 strcpy(str, buffer); } int main(int argc , char *argv[]){ int fd[2]; // 管道:子进程写,父进程读 pid_t childpid; // 创建管道 if (pipe(fd) == -1) { fprintf(stderr, "Pipe Failed\n"); return 1; } childpid = fork(); if (childpid < 0){ fprintf(stderr, "Fork Failed\n"); return 1; } else if(childpid == 0){ // 子进程:执行cat,把输出写到管道的写端 close(fd[0]); // 关闭不需要的读端 // 将stdout重定向到管道写端 dup2(fd[1], STDOUT_FILENO); close(fd[1]); // 重定向后可以关闭原写端 // 执行cat命令,cat会从stdin(终端)读取输入,输出到stdout(现在是管道) char* myargs[] = {"cat", NULL}; execvp(myargs[0], myargs); // 如果execvp失败才会走到这里 perror("execvp failed"); exit(1); } else { // 父进程:从管道读端读取cat的输出,处理后打印 close(fd[1]); // 关闭不需要的写端 char input_buf[1024] = {0}; ssize_t read_len; // 读取管道中的内容(cat的输出) while ((read_len = read(fd[0], input_buf, sizeof(input_buf)-1)) > 0) { input_buf[read_len] = '\0'; // 确保字符串结束 // 先输出原内容 printf("%s", input_buf); // 替换所有dog为fish(如需多次替换可循环调用replace_string) char *temp_pos = input_buf; while ((temp_pos = strstr(temp_pos, "dog")) != NULL) { replace_string(temp_pos, "dog", "fish"); temp_pos += strlen("fish"); // 跳过替换后的内容,避免重复替换 } // 输出转换后的内容 printf("%s", input_buf); } close(fd[0]); wait(NULL); // 等待子进程结束 } return 0; }
代码说明
- 管道使用:只需要一个管道就足够了,子进程把
cat的输出定向到管道写端,父进程从管道读端读取内容。 dup2的正确用法:dup2(fd[1], STDOUT_FILENO)让cat的标准输出指向管道的写端,这样cat的所有输出都会进入管道。- 字符串替换:优化了替换逻辑,支持单次输入中多次出现
dog的替换场景。 - 管道关闭:每个进程都关闭自己不需要的管道端,避免不必要的资源占用和阻塞。
测试效果
编译运行后,在终端输入dog并回车,会输出:
dog fish
如果输入dog dog,会输出:
dog dog fish fish
如果需要让原内容和转换内容在同一行输出,只需要调整printf的格式,比如把原内容的换行符去掉后再拼接转换内容即可。
内容的提问来源于stack exchange,提问作者Ramanpreet Kaur
相关产品推荐
相关产品推荐

