我自己的 shell 程序中的后台进程忽略标准输入
Background process in my own shell program to ignore stdin
我正在用 C 编写自己的 shell 小程序。当我 运行 将 child 进程作为后台进程时,我想忽略来自来自 parent 进程的用户。我目前正在尝试通过管道传输它然后关闭 child 的标准输入,但输入仍然转到 child.
else // A process
{
pid_t child_pid;
char lastArgument = args[currArgsIndex-1][0];
if (lastArgument != '&'){ //Normal process
if((child_pid = fork()) == 0) {
execvp(filepath, args);
exit(0);
}
else
{
while(wait(NULL) != child_pid);
}
}
else { // Background
args[currArgsIndex-1] = NULL;
int process_pipe[2];
pipe(process_pipe); // Piping
if((child_pid = fork()) == 0) {
close(process_pipe[0]); // Ignore stdin for child
execvp(filepath, args);
exit(0);
}
}
}
你创建了一个管道并关闭了读取端,但是你从来没有说管道应该是stdin。
听起来您的意图是 1. 仅在子进程中打开管道,2. 关闭 write
端以便无法读取数据,3. 将读取端设置为标准输入:
else { // Background
args[currArgsIndex-1] = NULL;
if((child_pid = fork()) == 0) {
int process_pipe[2];
pipe(process_pipe); // Piping
dup2(process_pipe[0], 0); // Copy read end as stdin
close(process_pipe[0]); // Close FD that is now unused
close(process_pipe[1]); // Close write end so no data can be read
execvp(filepath, args);
perror("execvp failed");
exit(1); // exit with error
}
}
虽然有一个管道是没有意义的。您可以更轻松地打开 /dev/null
进行读取并将其设置为标准输入。或者,只需完全关闭 stdin
(某些程序会报错):
else { // Background
args[currArgsIndex-1] = NULL;
if((child_pid = fork()) == 0) {
close(0); // Close stdin
execvp(filepath, args);
/* error handling */
}
请注意,真正的 shell 允许重定向到后台进程,在这种情况下,上述 none 将起作用:
wc -l < myfile &
真正的 shell 实际上根本不会关闭或重定向标准输入,而是会将命令放在它自己的进程组中,该进程组不控制终端。该进程在尝试从标准输入读取时将收到 SIGTSTP,然后您可以使用 fg
将其带到前台开始输入数据。
我正在用 C 编写自己的 shell 小程序。当我 运行 将 child 进程作为后台进程时,我想忽略来自来自 parent 进程的用户。我目前正在尝试通过管道传输它然后关闭 child 的标准输入,但输入仍然转到 child.
else // A process
{
pid_t child_pid;
char lastArgument = args[currArgsIndex-1][0];
if (lastArgument != '&'){ //Normal process
if((child_pid = fork()) == 0) {
execvp(filepath, args);
exit(0);
}
else
{
while(wait(NULL) != child_pid);
}
}
else { // Background
args[currArgsIndex-1] = NULL;
int process_pipe[2];
pipe(process_pipe); // Piping
if((child_pid = fork()) == 0) {
close(process_pipe[0]); // Ignore stdin for child
execvp(filepath, args);
exit(0);
}
}
}
你创建了一个管道并关闭了读取端,但是你从来没有说管道应该是stdin。
听起来您的意图是 1. 仅在子进程中打开管道,2. 关闭 write
端以便无法读取数据,3. 将读取端设置为标准输入:
else { // Background
args[currArgsIndex-1] = NULL;
if((child_pid = fork()) == 0) {
int process_pipe[2];
pipe(process_pipe); // Piping
dup2(process_pipe[0], 0); // Copy read end as stdin
close(process_pipe[0]); // Close FD that is now unused
close(process_pipe[1]); // Close write end so no data can be read
execvp(filepath, args);
perror("execvp failed");
exit(1); // exit with error
}
}
虽然有一个管道是没有意义的。您可以更轻松地打开 /dev/null
进行读取并将其设置为标准输入。或者,只需完全关闭 stdin
(某些程序会报错):
else { // Background
args[currArgsIndex-1] = NULL;
if((child_pid = fork()) == 0) {
close(0); // Close stdin
execvp(filepath, args);
/* error handling */
}
请注意,真正的 shell 允许重定向到后台进程,在这种情况下,上述 none 将起作用:
wc -l < myfile &
真正的 shell 实际上根本不会关闭或重定向标准输入,而是会将命令放在它自己的进程组中,该进程组不控制终端。该进程在尝试从标准输入读取时将收到 SIGTSTP,然后您可以使用 fg
将其带到前台开始输入数据。