在 C 中重现 bash 管道的行为
Reproducing the behavior of bash's pipes in C
我正在尝试使用 pipe
和 dup2
重现 bash 管道的行为,它对一个管道工作正常,因为第一个和最后一个管道要么输入或输出重定向,但是当我连续添加多个时它不起作用(当输入和输出都重定向到管道时),输入和输出似乎相互混淆,所以我们需要在两者之间睡觉吗每个命令?我在阅读文档时看到可执行文件同时 运行 并且我们不应该等待前一个子进程结束所以我不等待。这是我的代码的错误部分:
#include "shell.h"
static int pfd[2];
void ms_terminate(int ret) {
close(pfd[0]);
close(pfd[1]);
clean_exit(ret);
}
pid_t execute(const t_shcmd *cmd, char *const *envp, bool in, bool out) {
pid_t cpid = 0;
if (!ft_strcmp(cmd->av[0], "cd")) {
int fd_in = dup(0), fd_out = dup(1);
if (in) dup2(pfd[0], 0);
if (out) dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
builtin_cd(cmd->ac, cmd->av);
dup2(fd_in, 0);
dup2(fd_out, 1);
close(fd_in);
close(fd_out);
}
else if (!(cpid = fork())) {
if (in) dup2(pfd[0], 0);
if (out) dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
execve(*cmd->av, cmd->av, envp);
clean_exit(EXIT_FAILURE);
}
if (cpid == -1)
ms_terminate(EXIT_FAILURE);
return cpid;
}
void execute_pipeline(const t_shcmd *cmd, char *const *envp) {
pid_t cpid;
if (!(cpid = fork())) {
execute(cmd, envp, false, true);
while ((cmd = cmd->pipe)->pipe)
execute(cmd, envp, true, true);
execute(cmd, envp, true, false);
ms_terminate(EXIT_SUCCESS);
}
if (cpid == -1) ms_terminate(EXIT_FAILURE);
while (wait(NULL) > 0);
}
void ms_execute(const t_shcmd *cmd, char *const *envp) {
pid_t cpid;
pipe(pfd);
while (cmd) {
if (cmd->pipe)
execute_pipeline(cmd, envp);
else {
cpid = execute(cmd, envp, false, false);
wait(NULL);
}
cmd = cmd->next;
}
close(pfd[0]);
close(pfd[1]);
}
struct t_shcmd
基本上是一个像这样声明的特殊链表,并由我的解析器获取(顺便说一句,问题不是来自解析器,而是来自上面的代码):
typedef struct s_shcmd t_shcmd;
struct s_shcmd {
t_shcmd *next, *pipe;
int ac;
char *av[];
};
结构如下:
把管道想象成真正的管道。
如果要将来自 prog1
的信息传送到 prog2
,则需要一个管道。
如果您还想将来自 prog2
的信息传送到 prog3
,您将需要另一个管道。
所以prog1 | prog2 | prog3
需要两个管道。
注意:确保关闭所有不需要的管端。 prog1
应该只打开四个管端之一,prog2
应该只打开两个,prog3
应该只打开最后一个。
我正在尝试使用 pipe
和 dup2
重现 bash 管道的行为,它对一个管道工作正常,因为第一个和最后一个管道要么输入或输出重定向,但是当我连续添加多个时它不起作用(当输入和输出都重定向到管道时),输入和输出似乎相互混淆,所以我们需要在两者之间睡觉吗每个命令?我在阅读文档时看到可执行文件同时 运行 并且我们不应该等待前一个子进程结束所以我不等待。这是我的代码的错误部分:
#include "shell.h"
static int pfd[2];
void ms_terminate(int ret) {
close(pfd[0]);
close(pfd[1]);
clean_exit(ret);
}
pid_t execute(const t_shcmd *cmd, char *const *envp, bool in, bool out) {
pid_t cpid = 0;
if (!ft_strcmp(cmd->av[0], "cd")) {
int fd_in = dup(0), fd_out = dup(1);
if (in) dup2(pfd[0], 0);
if (out) dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
builtin_cd(cmd->ac, cmd->av);
dup2(fd_in, 0);
dup2(fd_out, 1);
close(fd_in);
close(fd_out);
}
else if (!(cpid = fork())) {
if (in) dup2(pfd[0], 0);
if (out) dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
execve(*cmd->av, cmd->av, envp);
clean_exit(EXIT_FAILURE);
}
if (cpid == -1)
ms_terminate(EXIT_FAILURE);
return cpid;
}
void execute_pipeline(const t_shcmd *cmd, char *const *envp) {
pid_t cpid;
if (!(cpid = fork())) {
execute(cmd, envp, false, true);
while ((cmd = cmd->pipe)->pipe)
execute(cmd, envp, true, true);
execute(cmd, envp, true, false);
ms_terminate(EXIT_SUCCESS);
}
if (cpid == -1) ms_terminate(EXIT_FAILURE);
while (wait(NULL) > 0);
}
void ms_execute(const t_shcmd *cmd, char *const *envp) {
pid_t cpid;
pipe(pfd);
while (cmd) {
if (cmd->pipe)
execute_pipeline(cmd, envp);
else {
cpid = execute(cmd, envp, false, false);
wait(NULL);
}
cmd = cmd->next;
}
close(pfd[0]);
close(pfd[1]);
}
struct t_shcmd
基本上是一个像这样声明的特殊链表,并由我的解析器获取(顺便说一句,问题不是来自解析器,而是来自上面的代码):
typedef struct s_shcmd t_shcmd;
struct s_shcmd {
t_shcmd *next, *pipe;
int ac;
char *av[];
};
结构如下:
把管道想象成真正的管道。
如果要将来自 prog1
的信息传送到 prog2
,则需要一个管道。
如果您还想将来自 prog2
的信息传送到 prog3
,您将需要另一个管道。
所以prog1 | prog2 | prog3
需要两个管道。
注意:确保关闭所有不需要的管端。 prog1
应该只打开四个管端之一,prog2
应该只打开两个,prog3
应该只打开最后一个。