[英]implementing pipes in C shell
我是編程初學者,我正在實現 C shell 中的管道。
我發現一些使用 STDIN 的命令 shell output 開始無法正常工作。 例如光標移動。
直接使用 STDIN cat | echo hello
的這種命令就是這種情況。 cat | echo hello
或tr | ls
tr | ls
我檢查了它是否與未關閉的 fd 無關...我在 dup2 后立即關閉 pipe 的寫入端。 我在 pipe 的寫入端的 pipe 期間關閉了子進程中 pipe 的讀取端。
這是代碼,抱歉有點亂,它使用一個 int term->redir->pipe_fd 數組來處理多個 pipe 情況:
// For each pipe, it creates the pipe in a new instance of the int array term->redir->pipe_fd.
int make_pipe(t_term *term)
{
int pipe_stack;
term->redir->pipe_stack++;
if (!((pipe_stack = term->redir->pipe_stack) < MAX_FD)
|| pipe(term->redir->pipe_fd[pipe_stack]) == -1)
{
err_dup();
return (close_pipe(term));
}
return (0);
}
// left_pipe dup2 the write end of (pipe[1]) to the STDOUT, and closes the pipe's write end.
int left_pipe(t_term *term)
{
int new_fd;
int pipe_stack;
new_fd = -1;
pipe_stack = term->redir->pipe_stack;
term->redir->pipe_write = 1;
if ((new_fd = dup2(term->redir->pipe_fd[pipe_stack][WRITE_END],
STDOUT_FILENO)) == -1)
ft_printf("[fd=2]21sh: %d: LEFT Bad file descriptor\n[/fd]",
term->redir->pipe_fd[pipe_stack][WRITE_END]);
close(term->redir->pipe_fd[pipe_stack][WRITE_END]);
term->redir->pipe_fd[pipe_stack][WRITE_END] = -1;
return ((new_fd == -1) ? 1 : 0);
}
// then, sh_exec is called, see below. The read end of the pipe is closes in the child processus.
// right pipe dup2 the STDIN whith the readend of the pipe (pipe[0]) and closes it.
int right_pipe(t_term *term)
{
int new_fd;
int pipe_stack;
new_fd = -1;
pipe_stack = term->redir->pipe_stack;
term->redir->pipe_write = 0;
if (pipe_stack > FD_INIT)
{
term->redir->pipe_read = 1;
if ((new_fd = dup2(term->redir->pipe_fd[pipe_stack][READ_END],
STDIN_FILENO)) == -1)
ft_printf("[fd=2]21sh: %d: RIGHT Bad file descriptor\n[/fd]",
term->redir->pipe_fd[pipe_stack][READ_END]);
close(term->redir->pipe_fd[pipe_stack][READ_END]);
term->redir->pipe_fd[pipe_stack][READ_END] = -1;
term->redir->pipe_stack--;
}
return ((new_fd == -1) ? 1 : 0);
}
在調用了左邊的 pipe 之后,它在下面調用了 exec function 並關閉了 pipe (pipe[0]) 的未使用的 read_end。 在調用了正確的 pipe 之后,它再次調用 exec function 來執行命令的正確部分:
void wait_pipe(char *cmd, int *status)
{
if (waitpid(-1, status, WNOHANG) == -1)
print_exec_error(cmd);
}
int sh_exec(char *path, char **cmd, t_term *term)
{
pid_t father;
int status;
status = 0;
father = fork();
if (father > 0 && term->redir->pipe_stack >= 0)
wait_pipe(*cmd, &status);
else if (father > 0)
{
if (waitpid(father, &status, 0) == -1)
print_exec_error(*cmd);
}
if (!father)
{
if (term->redir->pipe_write)
close(term->redir->pipe_fd[term->redir->pipe_stack][READ_END]);
if (execve(path, cmd, term->env) == -1)
{
ft_printf("[fd=2]Filetype unknown\n[/fd]");
exit(0);
}
err_not_found(*cmd);
}
return (status);
}
此外,我不明白使用以下命令cat | echo
cat | echo
。 它返回一行的提示然后停止,不太可能是單獨的cat
命令繼續並等待直到它收到停止信號。
如果有人有線索?
此外,我不明白使用以下命令
cat | echo
cat | echo
。 它返回一行的提示然后停止,不太可能是單獨的 cat 命令繼續並等待直到它收到停止信號。
我將嘗試解釋這里發生的事情:
$ cat | echo
foobar
$
第一個空行是echo
命令僅打印\n
到stdout
(因為它沒有任何參數),然后我得到提示,這是cat
等待輸入,我鍵入foobar
並按 enter( \n
)。 我懷疑cat
每行打印它的 output 行所以它試圖將foobar\n
寫入其stdout
,但它的stdout
是“管道”( |
)到echo
的stdin
和echo
已經退出關閉它的stdin
(因為他有沒什么可做的),所以cat
試圖寫入一個封閉的 pipe 並獲得SIGPIPE
。 SIGPIPE
的默認行為是結束進程。
運行strace
證實了這一切:
$ strace cat | echo
...
read(0, foobar
"foobar\n", 131072) = 7
write(1, "foobar\n", 7) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=6069, si_uid=1000} ---
+++ killed by SIGPIPE +++
$
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.