使用 pipe() 时无法退出 fork()
Can't quit a fork() when using pipe()
我正在重建一个完整的shell。为此,我必须模拟“|”。为此,我必须使用 dup2()、fork() 和 pipe() 函数。
我最成功的代码是这样的:
int exec_pipe(global *glob, char *commande)
{
int pipefd[2];
char **pipe_commandes = my_split(commande, '|');
char **left = my_str_to_word_array(pipe_commandes[0]);
char **right = my_str_to_word_array(pipe_commandes[1]);
int pid = 0;
int status;
pipe(pipefd);
pid = fork();
if (pid == 0) {
close(pipefd[1]);
dup2(pipefd[0], 0);
close(pipefd[0]);
glob->commande = right;
distribe_commande(glob);
glob->commande = NULL;
} else {
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);
glob->commande = left;
distribe_commande(glob);
glob->commande = NULL;
}
}
函数 distribe_commande() 导致命令格式化,以便在该函数中使用 execve() 执行:
void exec_path_commande(char *path, global *glob)
{
int pid;
int status;
pid = fork();
if (pid == 0) {
dup2(glob->fd, glob->origine);
if (execve(path, glob->commande, glob->env) == -1)
exit(0);
} else
while (waitpid(pid, &status, 0) != -1 && !WIFEXITED(status))
error_execve(status);
}
其中 char *path
是正确格式的命令。
我的问题是,当我发送命令时 ls | cat -e
命令工作:
$~> ls | cat -e
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
但是如果我向程序发送另一个命令,| cat -e
效果甚至在提示符下仍然存在,我不明白为什么:
$~> ls | cat -e
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
^[[0;31m^[[1m$^[[0;36m^[[1m~^[[0;32m^[[1m> ^[[0;37m^[[0mls
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
^[[0;31m^[[1m$^[[0;36m^[[1m~^[[0;32m^[[1m> ^[[0;37m^[[0m
提前感谢您的回答。
您 dup2
做错了地方。你也有一个 fork
太多了。
A redirect 应该是这样的(outline/pseudocode,不是真正的 C 代码):
fd = open(...)
pid = fork()
if (pid == 0)
dup2(fd, 1) // redirect the output, just an example
close(fd)
exec(...)
wait(...)
注意,dup2
和 close
在 fork
之后和 exec
之前。
A pipeline 是通过管道协调的两个(或更多)重定向,因此:
pipe(fds)
pid1 = fork()
if (pid1 == 0)
dup2(fds[0], 0)
close(fds[0])
close(fds[1])
exec(...)
pid2 = fork()
if (pid2 == 0)
dup2(fds[1], 1)
close(fds[0])
close(fds[1])
exec(...)
wait(...)
wait(...)
还请注意,两个 wait
都在两个 exec
之后。如果您以其他方式执行此操作 (exec-wait-exec-wait),则 yes | head
之类的命令将不起作用。
所以你需要重构 exec_path_commande
相当多。
我正在重建一个完整的shell。为此,我必须模拟“|”。为此,我必须使用 dup2()、fork() 和 pipe() 函数。
我最成功的代码是这样的:
int exec_pipe(global *glob, char *commande)
{
int pipefd[2];
char **pipe_commandes = my_split(commande, '|');
char **left = my_str_to_word_array(pipe_commandes[0]);
char **right = my_str_to_word_array(pipe_commandes[1]);
int pid = 0;
int status;
pipe(pipefd);
pid = fork();
if (pid == 0) {
close(pipefd[1]);
dup2(pipefd[0], 0);
close(pipefd[0]);
glob->commande = right;
distribe_commande(glob);
glob->commande = NULL;
} else {
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);
glob->commande = left;
distribe_commande(glob);
glob->commande = NULL;
}
}
函数 distribe_commande() 导致命令格式化,以便在该函数中使用 execve() 执行:
void exec_path_commande(char *path, global *glob)
{
int pid;
int status;
pid = fork();
if (pid == 0) {
dup2(glob->fd, glob->origine);
if (execve(path, glob->commande, glob->env) == -1)
exit(0);
} else
while (waitpid(pid, &status, 0) != -1 && !WIFEXITED(status))
error_execve(status);
}
其中 char *path
是正确格式的命令。
我的问题是,当我发送命令时 ls | cat -e
命令工作:
$~> ls | cat -e
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
但是如果我向程序发送另一个命令,| cat -e
效果甚至在提示符下仍然存在,我不明白为什么:
$~> ls | cat -e
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
^[[0;31m^[[1m$^[[0;36m^[[1m~^[[0;32m^[[1m> ^[[0;37m^[[0mls
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
^[[0;31m^[[1m$^[[0;36m^[[1m~^[[0;32m^[[1m> ^[[0;37m^[[0m
提前感谢您的回答。
您 dup2
做错了地方。你也有一个 fork
太多了。
A redirect 应该是这样的(outline/pseudocode,不是真正的 C 代码):
fd = open(...)
pid = fork()
if (pid == 0)
dup2(fd, 1) // redirect the output, just an example
close(fd)
exec(...)
wait(...)
注意,dup2
和 close
在 fork
之后和 exec
之前。
A pipeline 是通过管道协调的两个(或更多)重定向,因此:
pipe(fds)
pid1 = fork()
if (pid1 == 0)
dup2(fds[0], 0)
close(fds[0])
close(fds[1])
exec(...)
pid2 = fork()
if (pid2 == 0)
dup2(fds[1], 1)
close(fds[0])
close(fds[1])
exec(...)
wait(...)
wait(...)
还请注意,两个 wait
都在两个 exec
之后。如果您以其他方式执行此操作 (exec-wait-exec-wait),则 yes | head
之类的命令将不起作用。
所以你需要重构 exec_path_commande
相当多。