Как читать содержимое конвейера в C?

Я хочу иметь возможность сделать это:

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

Я знаю, что isatty следует использовать, чтобы определить, является ли stdin tty или нет. Если это не tty, я хочу прочитать содержимое конвейера - в приведенном выше примере, это строка hello world.

Какой рекомендуемый способ сделать это в C?

Вот что я получил до сих пор:

#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);
  }

}

Я скомпилировал это, используя:

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

Это почти работает, за исключением того, что всегда кажется, что добавлен U + FFFD REPLACEMENT CHARACTER и новая строка (я все же понимаю строку новой строки) в конце строки содержимого с каналами. Почему это происходит и как можно избежать этой проблемы?

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

Отказ от ответственности: У меня нет опыта работы с C. Пожалуйста, успокойся.

Ответ 1

Символ замены появляется, потому что вы забыли NUL - завершите строку.

Новая строка есть, потому что по умолчанию echo вставляет '\n' в конец вывода.

Если вы не хотите вставлять '\n', используйте это:

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

И чтобы удалить неправильную вставку символов

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

перед печатью текста.

Обратите внимание, что вам нужно использовать i-1 как нулевой символ, так как вы выполнили свой цикл теста. В вашем коде i добавляется еще один раз после последнего char.