Read from pipe line by line in C

55,707

Solution 1

This is usually just called reading from stdin. The program shouldn't care whether the input is a pipe, a redirected file, or a keyboard.

fread will just read until the buffer is full. Use fgets to read a line.

Also the buffer size should be big enough to hold the line. For little one-off programs, you can just pick a number. Or there's a standard name BUFSIZ which gives you a pretty-big buffer. How big? Big enough. Really? Probably.

fgets will copy the newline character in the string unless the string fills up first. So you can test the last character to tell if the line was truncated or not. With reasonable inputs, that's not going to happen. But a more robust approach would allocate a larger buffer, copy the partial line, and call fgets again tp keep trying to get a complete line.

#include <stdio.h>

int main() {
    char buf[BUFSIZ];
    fgets(buf, sizeof buf, stdin);
    if (buf[strlen(buf)-1] == '\n') {
        // read full line
    } else {
        // line was truncated
    }
    return 0;
}

This gets you halfway to being protected from the dreaded buffer overflow problem. fgets will not write more than the size passed to it. The other half, as mentioned above, is doing something sensible with the possible partial lines that may result from unexpectedly long input lines.

Solution 2

Here's another option (I am not totally sure it is a 'proper' way)- use the number of bytes read by the read function. In this example I was reading from stdin although a redirection was made so the fd in 0 is a file/pipe/whatever you need it to be.

  while ((nbytes=read(STDIN_FILENO, buffer, MAX_PIPE_SIZE)) > 0) {
    write(STDOUT_FILENO, buffer, nbytes);
  }
Share:
55,707
bladepit
Author by

bladepit

Updated on December 17, 2020

Comments

  • bladepit
    bladepit over 3 years

    How can I separate the lines which are coming from a pipe. In the pipe there is this text:

    HALLO:500\n
    TEST:300\N
    ADAD
    ADAWFFA
    AFAGAGAEG
    

    I want to separate the lines from the pipe because i want to save the values in variables.

    Here is my c code:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define BUFFERSIZE    1
    
    int main(int argc, char **argv){
        unsigned char     buffer[BUFFERSIZE];
        FILE                         *instream;
        int                            bytes_read=0;
        int                            buffer_size=0;
    
    
        buffer_size=sizeof(unsigned char)*BUFFERSIZE;
        /* open stdin for reading */
        instream=fopen("/dev/stdin","r");
    
        /* did it open? */
        if(instream!=NULL){
            /* read from stdin until it's end */
            while((bytes_read=fread(&buffer, buffer_size, 1, instream))==buffer_size){
                fprintf(stdout, "%c", buffer[0]);
            }
        }
        /* if any error occured, exit with an error message */
        else{
            fprintf(stderr, "ERROR opening stdin. aborting.\n");
            exit(1);
        }
    
        return(0);
    }
    

    Is this the right way to read from pipe for the best line by line?

  • luser droog
    luser droog about 11 years
    I would. But you should learn to do man fgets for yourself. (It's the first thing I would do to write an example. I always get the arguments backwards when I write without checking.)
  • luser droog
    luser droog about 11 years
    I'm not trying to sound snotty. I really think it's best for me not to write such an example.
  • Anish Ramaswamy
    Anish Ramaswamy about 11 years
    @bladepit, Or, an online manual should help you :)
  • bladepit
    bladepit about 11 years
    Yeah thats right. I look at the manual and hope till this afternoon i have fixed my problem
  • bladepit
    bladepit about 11 years
    one last question: with fgets i need to specific the length of the line which i read?
  • luser droog
    luser droog about 11 years
    You need to specify a maximum length. It will stop at the newline. Oh, alright, I'll add more to the answer. But you should always have manpages installed. They're super useful.
  • wastl
    wastl over 4 years
    In addition to BUFSIZ, there is also LINE_MAX (<limits.h>). It's less (2048 vs 8192) on my machine.