c - 模拟命令行提示符的 C 程序
问题描述
我正在尝试实现一个类似于 Linux shell 命令提示符的小型 C 程序$ sort < Names.txt | uniq | wc - l
。为此,我使用 execlp 运行命令
生成的程序将对任意名称列表进行排序并删除重复项。它对列表进行排序,因为它需要相邻的重复行才能删除。然后只计算行数。
gcc -o sortuniqwc sortuniqwc.c
我已经发布了我的代码,它目前只是在我编译和运行后被挂断./sortuniqwc < Names.txt
。如果我注释掉 fd 的管道,每个系统调用似乎都能正常执行。我不确定为什么它没有正确地将进程传递给系统调用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *arv[])
{
pid_t pid;
int fd1[2]; //making file descriptor 1
if (pipe(fd1) == -1)
{
fprintf(stderr, "pipe failed");
return 1;
}
pid = fork(); //first child for sort
//printf("the pid for pipe parent is %d and the child pid is %d", getppid(), getpid());
if (pid < 0)
{
fprintf(stderr, "fork error");
return 1;
}
if (pid == 0)
{
dup2(fd1[1], 1);
close(fd1[0]);
//printf("the child process running sort is %d\n", getpid());
execlp("sort", "sort", NULL);
printf("sort exec - should not be here");
exit(0);
}
wait(0);
int fd2[2];
if (pipe(fd2) == -1)
{
fprintf(stderr, "pipe failed");
return 1;
}
pid = fork(); //second child for uniq
if (pid < 0)
{
fprintf(stderr, "fork error\n");
return 1;
}
if (pid == 0)
{
dup2(fd1[0], 0);
dup2(fd2[1], 1);
close(fd1[1]);
close(fd2[0]);
//printf("the child process running uniq is %d\n", pid);
execlp("/usr/bin/uniq", "uniq", NULL);
printf("uniq exec - you shouldnt be here");
exit(0);
}
wait(0);
pid = fork(); //3rd child process for wc
if (pid < 0)
{
fprintf(stderr, "fork failed\n");
return 1;
}
if (pid == 0)
{
dup2(fd2[0], 0);
close(fd2[1]);
close(fd1[0]);
close(fd1[1]);
//printf("the child process running wc is %d\n", getpid());
execlp("wc", "wc", "-l", NULL);
printf("wc exec - you shouldnt be here\n");
exit(0);
}
//parent
close(fd1[0]);
close(fd1[1]);
close(fd2[0]);
close(fd2[1]);
wait(NULL);
printf("CHILD COMPLETE \n");
}
解决方案
TL;DR - 父级需要close()
将管道写入端的副本附加到sort
' 的输出。close(fd1[1])
在第一次等待“修复”问题之前添加。
程序在第二次调用中“挂起” wait()
(等待uniq
孩子退出1)。但是,uniq
永远不会退出,因为它连接到fd1
管道读取端的标准输入永远不会关闭。系统中有这个文件描述符的两个副本:第一个属于 的子进程exec
,sort
并且它确实按预期关闭sort
。但是另一个副本属于不属于它的父进程close()
。由于管道的写入端至少还有一个打开的文件描述符,因此管道没有关闭。
该解决方案还要求将整个排序输出缓冲在管道中(即在内核中)。对于非平凡的输入,最好以相反的顺序分叉子节点,连接它们的所有管道,并让它们并行运行。这更接近于真正的、健壮的外壳所能做的。
1或接收信号等,稳健的外壳应检查该信号。
推荐阅读
- batch-file - 如何使用批处理将文件中的旧文本替换为新输入?
- oracle - 如何使用 plsql 返回多列
- php - 在 codeigniter (dmY) 中输入日期
- python - Tkinter 对象的“ID”和“标签”之间的区别
- jquery - cPanel Css 警报
- pyspark - Sagemaker PySpark:内核死机
- asp.net-core - 如何在 asp.et core 中获取 IFormFile / FormFile 对象
- java - java中的正则表达式匹配和替换
- java - AbstractQueuedSynchronizer 条目的 acquireQueued 方法何时会最终阻塞?
- codenameone - Codenameone - 表格上的透明度或样式问题