5

Given the following code, why does cat only print the contents of the pipe after I've typed \n or CTRL+D? What are the conditions for cat to actually print what it read?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void){
    int pid,p[2];
    char ch;
    pipe(p);
    if((pid=fork()) == -1){
        fprintf(stderr,"Error:can't create a child!\n");
        exit(2);
    }
    if(pid){
        close(p[0]);
        while((ch=getchar())!=EOF){
            write(p[1],&ch,1);
        }
        close(p[1]);
        wait(0);
    }else{
        close(p[1]);
        close(0);
        dup(p[0]);
        close(p[0]);
        execlp("cat","cat",NULL);
    }
    return 0;
}
PersianGulf
  • 10,850

2 Answers2

5

That has nothing to do with cat, pipes or buffering. Your "problem" is upstreams, at the terminal device.

If every character you enter at the keyboard in the terminal was available for reading by your application immediately and cat, then would you enter aBackspacebReturn, your application would read a then ^? then b then ^M, which is not what you want and is not what you get.

What you want and get is for it to read a^J instead.

You get that because in the default canonical mode, the terminal device driver (the tty line discipline) implements a line editor that lets you enter text and edit it (with limited capabilities), and the text you enter is only available for reading when you press Return.

To avoid that, you can tell the terminal device to leave that canonical mode. For instance, by doing stty raw, and you'll see your application and cat get the characters immediately, but probably the behaviour is not what you expect.

You'll also notice that for other types of input, like a pipe, characters are output as soon as they arrive as in :

(printf x; sleep 1; echo y) | that-command
  • Thank you and everyone else for answering. I was suspecting it wasn't related to anything that I knew, but had to ask somehow. – Mmc Dispenser May 09 '15 at 07:48
-2

follow this loop:

while((ch=getchar())!=EOF)
{
        write(p[1],&ch,1);
}

with:

char carriageReturn = 0x0D;
write( p[1], &carriageReturn, 1 );