简体   繁体   English

C:将子进程输出重定向到其他子进程输入和标准输出

[英]C : Redirect child process output to other child process input and stdout

I am a bit of a newbie in programming Linux in C (I searched for similar threads but none helped), so I got stuck at the following problem : 我是使用C语言进行Linux编程的新手(我搜索了类似的线程,但没有帮助),所以我陷入了以下问题:

I want to create a shell in C for Linux (using fork(), exec(), pipe(), that gets a command with parameters and pipes as input from the terminal stdin (ex. "sort foo | uniq -c | wc -l"), it executes it and then asks for the next command etc. 我想在Linux的C语言中创建一个shell(使用fork(),exec(),pipe(),该命令从终端stdin中获取带有参数和管道的命令作为输入(例如,“ sort foo | uniq -c | wc -l“),则执行该命令,然后要求下一个命令,等等。

I separated the different commands, their parameters etc, I created 1 child process for each one, but I can't chain the output of each child process to the input of the next one (and the last output at stdout in terminal). 我分离了不同的命令,它们的参数等,为每个命令创建了一个子进程,但是无法将每个子进程的输出链接到下一个命令的输入(以及终端中stdout的最后一个输出)。

Could anyone help do the correct piping to get it up and running ?? 任何人都可以帮助做正确的管道安装和运行吗?

For any more info, just ask... Thanks in advance 有关更多信息,请问...预先感谢

The full code is below: 完整的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h> 
#include <unistd.h>

#define P_READ 0
#define P_WRITE 1

pid_t pID, chID;
char input[100];
char * params[100][100];
char * funcs[100];
char * par;
char * fun;
int i, j, k, stat, infd[2], outfd[2];


//Pipe read
void read_en(int * infd)
{
    dup2(infd[P_READ], STDIN_FILENO);
    close(infd[P_READ]);
    close(infd[P_WRITE]);
}

//Pipe write
void write_en(int * outfd)
{
    dup2(outfd[P_WRITE], STDOUT_FILENO);
    close(outfd[P_READ]);
    close(outfd[P_WRITE]);
}

//Fork, read from pipe, write to pipe, exec   
void fork_chain(int * infd, int * outfd, int i)
{
        pID = fork();

        if (pID == 0)
        {
            if (infd != NULL)
            {
                read_en(infd);
            }

            if (outfd != NULL)
            {
                write_en(outfd);
            }

            execvp(params[i][0], params[i]);
            fprintf(stderr, "Command not found!\n");
            exit(1);
        }
        else if (pID < 0)
        {
            fprintf(stderr, "Fork error!\n");
            exit(1);
        }
        else
        {
            chID = waitpid(-1, &stat, 0);
        }
}


int main()
{
    printf("\n$");
    fgets(input, sizeof(input), stdin);
    strtok(input, "\n");


    while (strcmp(input, "exit") != 0)
    {
        //Separate each command
        k = 0;
        fun = strtok(input, "|");

        while (fun != NULL)
        {
            funcs[k] = fun;
            fun = strtok(NULL, "|");
            k++;
        }


        //Separate each command's parameters
        for (i = 0; i < k; i++)
        {
            j = 0;
            par = strtok(funcs[i], " ");

            while (par != NULL)
            {
                params[i][j] = par;
                par = strtok(NULL, " ");
                j++;
            }
            params[i][j] = NULL;
        }

        //Fork, pipe and exec for each command
        for (i = 0; i < k; i++)
        {
            if (i == 0)
            {
                pipe(outfd);
                fork_chain(NULL, outfd, 0);
                infd[P_READ] = outfd[P_READ];
                infd[P_WRITE] = outfd[P_WRITE];
            }
            else if (i == k-1)
            {
                fork_chain(infd, NULL, 1);
                close(infd[P_READ]);
                close(infd[P_WRITE]);
            }
            else
            {
                pipe(outfd);
                fork_chain(infd, outfd, i);
                close(infd[P_READ]);
                close(infd[P_WRITE]);
                infd[P_READ] = outfd[P_READ];
                infd[P_WRITE] = outfd[P_WRITE];
            }
        }

        //Ask for next input
        printf("\n$");
        fgets(input, sizeof(input), stdin);
        strtok(input, "\n");
    }

    return (0);
}

The shell process must close the write end of the pipe, because otherwise the child process does not get EOF on its input and blocks forever when calling read() . Shell进程必须关闭管道的写端,因为否则子进程将不会在其输入上获得EOF并在调用read()时永远阻塞。 Your code would close the write end, but too late in case of the last child, because fork_chain() waits for it to exit (which bears another problem if the pipe buffer gets full) before returning. 您的代码将关闭写入端,但是对于最后一个子fork_chain()fork_chain()已晚,因为fork_chain()等待它退出(如果管道缓冲区已满,这会带来另一个问题),然后再返回。 If we close the write end at the right time, the close(infd[P_WRITE]) has to be removed from read_en() , since it will already be closed by then. 如果我们在正确的时间关闭写入端,则必须从read_en()移除close(infd[P_WRITE]) read_en() ,因为届时它已经被关闭。
Aside, there is an error due to the code multiplication at 另外,由于代码乘法运算会导致错误

            else if (i == k-1)
            {
                fork_chain(infd, NULL, 1);

the argument 1 is only correct if k equals 2, in the general case it must be i . 仅当k等于2时,参数1才是正确的,通常情况下必须为i

So, along with the change in read_en() , the main fork-pipe-and-exec loop could be rewritten to 因此,随着read_en()的更改,主fork-pipe-and-exec循环可以重写为

        for (i = 0; i < k; i++)
        {
            fork_chain(i ? infd : NULL, i < k-1 ? pipe(outfd), outfd : NULL, i);
            if (i)
                close(infd[P_READ]);
            if (i < k-1)
                infd[P_READ] = outfd[P_READ],
                close(outfd[P_WRITE]);  // shell is done with it
        }

(note that infd[P_WRITE] is no longer used anywhere). (请注意, infd[P_WRITE]不再在任何地方使用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM