How to read piped content in C?

2019-05-14 16:16发布

问题:

I want to be able to do this:

$ echo "hello world" | ./my-c-program
piped input: >>hello world<<

I know that isatty should be used to detect if stdin is a tty or not. If it’s not a tty, I want to read out the piped contents — in the above example, that’s the string hello world.

What’s the recommended way of doing this in C?

Here’s what I got so far:

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

int main(int argc, char* argv[]) {

  if (!isatty(fileno(stdin))) {
    int i = 0;
    char pipe[65536];
    while(-1 != (pipe[i++] = getchar()));
    fprintf(stdout, "piped content: >>%s<<\n", pipe);
  }

}

I compiled this using:

gcc -o my-c-program my-c-program.c

It almost works, except it always seems to add a U+FFFD REPLACEMENT CHARACTER and a newline (I do understand the newline though) at the end of the piped content string. Why does this happen, and how can this issue be avoided?

echo "hello world" | ./my-c-program
piped content: >>hello world
�<<

Disclaimer: I have no experience with C whatsoever. Please go easy on me.

回答1:

The replacement symbol shows up because you forgot to NUL-terminate the string.

The newline is there because by default, echo inserts '\n' at the end of its output.

If you want to not insert '\n' use this:

echo -n "test" | ./my-c-program

And to remove the wrong character insert

pipe[i-1] = '\0';

before printing the text.

Note that you need to use i-1 as the null character because the way you implemented your loop test. In you code i is incremented once more after the last char.



标签: c stdin pipe