hiaslosch17
hiaslosch17

Reputation: 67

Why does the child process executing uniq -d not print duplicates passed by pipe over stdin?

I am currently writing a program which creates a child process using fork(). This child process shall execute the shell command "uniq" with the option "-d" so it reads from stdin. After the execute command I want to send strings as stdin over a pipe for the "uniq" program. So after I send the same string behind each other the string should be printed on stdout (see uniq man page: https://linux.die.net/man/1/uniq). But nothing is printed.

Here is my code so far:

void execute_uniq_process()
{
    //create pipe
    int pipefd[2];
    if(pipe(pipefd)<0)
    {
        //error handling
    }

    //create argv for command:
    char *argv[] = {"uniq","-d",(char *)0};

    //create child process
    pid_t pid = fork();
    int status;

    switch(pid)
    {
        case -1:
        //error handling
        break;

        case 0:
            //child process
            //close writing end in pipe
            close(pipefd[1]);

            //duplicate stdin
            dup2(pipefd[0],STDIN_FILENO);
            close(pipefd[0]);

            execvp("uniq",argv);
            exit(errno);
        break;

        default:
            //parent process
            //close reading end in pipe
            close(pipefd[0]);

            //write all commands to pipe
            write(pipefd[1],"test1",5);
            write(pipefd[1],"test1",5);
            write(pipefd[1],"test2",5);
            //edited:
            close(pipefd[1]);

            //waits till child is finished
            wait(&status);

            if(WEXITSTATUS(status) != EXIT_SUCCESS)
            {
                //error handling
            }
        break;
    } 
}

So I would expect that there is printed "test1" in the shell. I also wonder how to terminate the uniq process cleanly. I think there could probably be a issue with write, so that I have to simulate an "enter" after every string I write in the pipe.

Upvotes: 0

Views: 127

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754000

You have to close the pipe before waiting for uniq to finish, because it won't know it's got EOF until you close the pipe. And you've not written even one line to the standard input of uniq because there isn't a newline in the data that was written. The write() system call writes only what you tell it to write; it certainly doesn't add any newlines of its own volition.

Those changes, and sundry trivia, lead to:

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

int main(void)
{
    int pipefd[2];
    if (pipe(pipefd) < 0)
    {
        fprintf(stderr, "Failed to create pipe\n");
        return 1;
    }

    char *argv[] = {"uniq", "-d", (char *)0};

    pid_t pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "Failed to fork\n");
        return 1;

    case 0:
        close(pipefd[1]);
        dup2(pipefd[0], STDIN_FILENO);
        close(pipefd[0]);
        execvp(argv[0], argv);
        fprintf(stderr, "Failed to exec %s\n", argv[0]);
        exit(errno);

    default:
        close(pipefd[0]);
        write(pipefd[1], "test1\n", 6);
        write(pipefd[1], "test1\n", 6);
        write(pipefd[1], "test2\n", 6);
        close(pipefd[1]);
        int status;
        int corpse = wait(&status);

        if (WEXITSTATUS(status) != EXIT_SUCCESS)
        {
            fprintf(stderr, "Child (%s) exited (PID %d, status 0x%.4X)\n", argv[0], corpse, status);
        }
        break;
    }
    return 0;
}

This outputs test1 when it is run.

Upvotes: 0

Related Questions