我自己的 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 将其带到前台开始输入数据。