带有 tmpfile 的 Heredoc
Heredoc with tmpfile
我正在编写我的 minishell 版本并尝试在 C 中实现 heredoc (<<
)。我决定使用 tmpfile - 首先我将数据从 stdin
写入 tmpfile 直到到达分隔符,然后我使用 dup2
将程序的标准输入更改为 tmpfile 的 fd
,然后尝试使用 execve
.
执行 cat
命令
我试图简化程序并包含以下所有相关功能:
int main(int argc, char **argv, char **env)
{
t_shell shell;
ft_parse_envs_to_lst(&envs, env); // transform env to linked list
shell.tmpfile = "path to tmpfile";
while (1)
{
char *buf = readline("bash: ");
add_history(buf);
shell.std_in = dup(0);
shell.std_out = dup(1);
shell.f_in = dup(0);
shell.f_out = dup(1);
/* Token is represented by linked list. "cat << eof" translates into "cat" -> ">>" -> "eof",
with token pointing to "cat" */
t_token *token = parse_buffer(buf); // parse_buffer will return pointer to the first token
ft_execute_token(shell, token, env);
free(buf);
}
}
void ft_execute_token(t_shell *shell, t_token *token, t_envs_lst *env)
{
process_next_cmd(shell, token, env);
close(shell->f_in);
close(shell->f_out);
dup2(shell->std_in, STDIN_FILENO);
dup2(shell->std_out, STDOUT_FILENO);
close(shell->std_in);
close(shell->std_out);
}
void process_next_cmd(t_shell *shell, t_token *token, t_envs_lst *env)
{
t_token *prev = ft_get_prev_token(token); // get prev separator (for example, <<) or NULL
t_token *next = ft_get_next_token(token); // get next separator (for example, <<) or NULL
if (prev && (prev->type == DOBINP)) // "<<" will be marked as DOBINP
ft_handle_dobinp(shell, token);
if (next)
process_next_cmd(shell, next->next, env); // recursively go to the next command
if (!prev) // won't run any command on the part after "<<"" but will run "cat"
{
ft_execute_cmd(token, env); // just execve on child process (created with fork), whilst parent is waiting for child
if (next && next->type == DOBINP) // delete tmpfile
{
char **argv = malloc(sizeof(char *) * 3);
argv[0] = "/bin/rm";
argv[1] = shell->tmpfile;
argv[2] = NULL;
pid_t pid = fork();
if (pid == 0)
execve("/bin/rm", argv, NULL);
}
}
}
void handle_dobinp(t_shell *shell, t_token *token)
{
int rd;
int fd;
int buf_size;
char *buf;
fd = open(shell->tmpfile, O_TRUNC | O_CREAT | O_WRONLY, 0777);
buf_size = strlen(token->str);
buf = malloc(buf_size + 1);
printf("program: Start\n");
rd = read(STDIN_FILENO, buf, buf_size);
while (rd > 0)
{
buf[rd] = '[=10=]';
printf("program: Looping (read %s)", buf);
if (strncmp(buf, token->str, buf_size + 1) == 0)
break ;
write(fd, buf, rd);
rd = read(STDIN_FILENO, buf, buf_size);
}
free(buf);
close(fd);
shell->f_in = open(shell->tmpfile, O_RDONLY, 0777);
dup2(shell->f_in, STDIN_FILENO);
close(shell->f_in);
}
我想执行cat << eof
命令。一切正常,但我面临 handle_dobinp
函数中重复输出(测试期间)的问题。此外,在 main
中的 while
循环中又发生了一次迭代,输入为空(即程序执行了空命令)。
只有一个进程运行,所以我不确定这种行为的原因是什么?
更新: 我根据 评论更新了程序的输出。
bash$ cat << eof
program: Start
foo
program: Looping (read foo
)
bar
program: Looping (read bar)
program: Looping (read
)
eof
program: Looping (read eof)
foo
bar
bash$
bash$
改进您的日志记录。我想你的输出是正确的,但看起来像
bash$ cat << eof
program: Start
foo
program: Looping (read "foo")
program: Looping (read "\n")
bar
program: Looping (read "bar")
program: Looping (read "\n")
eof
program: Looping (read "eof")
program: foo
program: bar
bash$
bash$
我正在编写我的 minishell 版本并尝试在 C 中实现 heredoc (<<
)。我决定使用 tmpfile - 首先我将数据从 stdin
写入 tmpfile 直到到达分隔符,然后我使用 dup2
将程序的标准输入更改为 tmpfile 的 fd
,然后尝试使用 execve
.
cat
命令
我试图简化程序并包含以下所有相关功能:
int main(int argc, char **argv, char **env)
{
t_shell shell;
ft_parse_envs_to_lst(&envs, env); // transform env to linked list
shell.tmpfile = "path to tmpfile";
while (1)
{
char *buf = readline("bash: ");
add_history(buf);
shell.std_in = dup(0);
shell.std_out = dup(1);
shell.f_in = dup(0);
shell.f_out = dup(1);
/* Token is represented by linked list. "cat << eof" translates into "cat" -> ">>" -> "eof",
with token pointing to "cat" */
t_token *token = parse_buffer(buf); // parse_buffer will return pointer to the first token
ft_execute_token(shell, token, env);
free(buf);
}
}
void ft_execute_token(t_shell *shell, t_token *token, t_envs_lst *env)
{
process_next_cmd(shell, token, env);
close(shell->f_in);
close(shell->f_out);
dup2(shell->std_in, STDIN_FILENO);
dup2(shell->std_out, STDOUT_FILENO);
close(shell->std_in);
close(shell->std_out);
}
void process_next_cmd(t_shell *shell, t_token *token, t_envs_lst *env)
{
t_token *prev = ft_get_prev_token(token); // get prev separator (for example, <<) or NULL
t_token *next = ft_get_next_token(token); // get next separator (for example, <<) or NULL
if (prev && (prev->type == DOBINP)) // "<<" will be marked as DOBINP
ft_handle_dobinp(shell, token);
if (next)
process_next_cmd(shell, next->next, env); // recursively go to the next command
if (!prev) // won't run any command on the part after "<<"" but will run "cat"
{
ft_execute_cmd(token, env); // just execve on child process (created with fork), whilst parent is waiting for child
if (next && next->type == DOBINP) // delete tmpfile
{
char **argv = malloc(sizeof(char *) * 3);
argv[0] = "/bin/rm";
argv[1] = shell->tmpfile;
argv[2] = NULL;
pid_t pid = fork();
if (pid == 0)
execve("/bin/rm", argv, NULL);
}
}
}
void handle_dobinp(t_shell *shell, t_token *token)
{
int rd;
int fd;
int buf_size;
char *buf;
fd = open(shell->tmpfile, O_TRUNC | O_CREAT | O_WRONLY, 0777);
buf_size = strlen(token->str);
buf = malloc(buf_size + 1);
printf("program: Start\n");
rd = read(STDIN_FILENO, buf, buf_size);
while (rd > 0)
{
buf[rd] = '[=10=]';
printf("program: Looping (read %s)", buf);
if (strncmp(buf, token->str, buf_size + 1) == 0)
break ;
write(fd, buf, rd);
rd = read(STDIN_FILENO, buf, buf_size);
}
free(buf);
close(fd);
shell->f_in = open(shell->tmpfile, O_RDONLY, 0777);
dup2(shell->f_in, STDIN_FILENO);
close(shell->f_in);
}
我想执行cat << eof
命令。一切正常,但我面临 handle_dobinp
函数中重复输出(测试期间)的问题。此外,在 main
中的 while
循环中又发生了一次迭代,输入为空(即程序执行了空命令)。
只有一个进程运行,所以我不确定这种行为的原因是什么?
更新: 我根据
bash$ cat << eof
program: Start
foo
program: Looping (read foo
)
bar
program: Looping (read bar)
program: Looping (read
)
eof
program: Looping (read eof)
foo
bar
bash$
bash$
改进您的日志记录。我想你的输出是正确的,但看起来像
bash$ cat << eof
program: Start
foo
program: Looping (read "foo")
program: Looping (read "\n")
bar
program: Looping (read "bar")
program: Looping (read "\n")
eof
program: Looping (read "eof")
program: foo
program: bar
bash$
bash$