我实际上正在研究在 shell 中实现多管道,我必须说我在解决项目中遇到的问题时遇到了一些问题。
一个特殊的细节使这种多管道实现非常困难,它必须在文件描述符的限制非常低的情况下工作。
例如,如果您在 bash 或 tcsh 上输入命令“limit descriptors 10”,您仍然可以运行很长的命令,例如“ls|cat|cat|cat|cat|cat|cat|cat|cat|cat|cat| cat|wc" 没有任何错误消息或损坏的管道。
我的 multipipe 也必须这样做。
我一直在研究这个问题并想出了几个不同的版本。最后一个似乎部分工作,但不符合真实外壳的显示。我所做的是创建一个执行命令“cat|ls|wc”行的树。
在真正的 shell 中,“wc”应该显示它的结果,然后“cat”应该在退出之前等待接收一个用户输入。
在我的版本中,“猫”循环首先出现,等待用户输入,然后让 wc 显示它的结果并退出。
我的“wc”显示了良好的结果,它的执行似乎被延迟了。就好像它正在等待接收来自管道或其他东西的信号......我无法弄清楚为什么“wc”没有立即显示我可能没有正确关闭或重复管道?
您会在这些行之后找到我的代码。
提前感谢您可以给我的任何帮助或提示。
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#define PIPE 1
#define CMD 2
typedef struct s_tree
{
char *cmd;
int fd[2];
char type;
struct s_tree *left;
struct s_tree *right;
struct s_tree *parent;
} t_tree;
/*
static void test_tree(t_tree *tree)
{
if (tree == NULL)
{
printf("Null\n");
return ;
}
if (tree->type == PIPE)
printf("Type pipe\n");
else if (tree->type == CMD)
printf("Type cmd : %s\n", tree->cmd);
if (tree->left != NULL)
{
printf("Gauche\n");
test_tree(tree->left);
}
if (tree->right != NULL)
{
printf("Droite\n");
test_tree(tree->right);
}
}
*/
void my_exit(int value)
{
fprintf(stderr, "EXITING %d\n", value);
perror(NULL);
exit(value);
}
int execute_cmd(t_tree *tree)
{
if (execlp(tree->cmd, tree->cmd, NULL) < 0)
my_exit(11);
return (0);
}
int execute_pipe(t_tree *tree)
{
int statusleft;
int statusright;
pid_t pidright;
pid_t pidleft;
int fd[2];
if (pipe(fd) < 0)
my_exit(1);
if ((pidleft = fork()) < 0)
my_exit(2);
if (pidleft == 0)
{
if (close(fd[1]) < 0
|| close(0) < 0)
my_exit(3);
if (dup2(fd[0], 0) < 0)
my_exit(4);
if (tree->left->type == PIPE)
return (execute_pipe(tree->left));
else if (tree->left->type == CMD)
return (execute_cmd(tree->left));
}
else
{
if (close(fd[0]) < 0
|| close(1) < 0)
my_exit(6);
if ((pidright = fork()) < 0)
my_exit(5);
if (pidright == 0)
{
if (dup2(fd[1], 1) < 0)
my_exit(7);
if (tree->right->type == PIPE)
return (execute_pipe(tree->right));
else if (tree->right->type == CMD)
return (execute_cmd(tree->right));
}
else
{
if (close(fd[1]) < 0
|| close(0) < 0)
my_exit(8);
if (waitpid(pidright, &statusright, 0) < 0)
my_exit(9);
}
if (waitpid(pidleft, &statusleft, 0) < 0)
my_exit(10);
}
return (0);
}
/*
** PIPE
** /\
** / \
** / \
** wc PIPE
** /\
** / \
** / \
** ls cat
**
** cat | ls | wc
*/
int main(int ac, char **av)
{
t_tree *tree;
tree = malloc(sizeof(*tree));
tree->left = malloc(sizeof(*tree));
tree->right = malloc(sizeof(*tree));
tree->right->left = malloc(sizeof(*tree));
tree->right->right = malloc(sizeof(*tree));
tree->type = PIPE;
tree->left->right = NULL;
tree->left->left = NULL;
tree->left->type = CMD;
tree->left->cmd = malloc(strlen("/usr/bin/wc") + 1);
strcpy(tree->left->cmd, "/usr/bin/wc");
tree->right->type = PIPE;
tree->right->left->right = NULL;
tree->right->left->left = NULL;
tree->right->left->type = CMD;
tree->right->left->cmd = malloc(strlen("/bin/ls") + 1);
strcpy(tree->right->left->cmd, "/bin/ls");
tree->right->right->left = NULL;
tree->right->right->left = NULL;
tree->right->right->type = CMD;
tree->right->right->cmd = malloc(strlen("/bin/cat") + 1);
strcpy(tree->right->right->cmd, "/bin/cat");
tree->parent = NULL;
tree->left->parent = tree;
tree->right->parent = tree;
tree->right->left->parent = tree->right;
tree->right->right->parent = tree->right;
/*test_tree(tree);*/
return (execute_pipe(tree));
}