Запись на stdin и чтение из stdout (программирование UNIX/LINUX/C)

Я работал над назначением, где программа приняла дескриптор файла в качестве аргумента (как правило, из родителя в вызове exec), и прочитала его из файла и написала в дескриптор файла, и в ходе тестирования я понял, что программа будет работать из командной строки и не давать ошибку, если я использовал 0, 1 или 2 в качестве дескриптора файла. Это имело смысл для меня, за исключением того, что я мог написать stdin и показать его на экране.

Есть ли объяснение этому? Я всегда думал, что есть некоторая защита на stdin/stdout, и вы, конечно же, не можете fprintf для stdin или fgets из stdout.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    char message[20];
    read(STDOUT_FILENO, message, 20);
    write(STDIN_FILENO, message, 20);

    return 0;
}

Ответы

Ответ 1

Попытка записать файл, помеченный как readonly или наоборот, приведет к тому, что write и read будут возвращать -1 и сбой. В этом конкретном случае stdin и stdout на самом деле являются одним и тем же файлом. По сути, перед выполнением вашей программы (если вы не выполняете никакого перенаправления) оболочка идет:

  if(!fork()){
       <close all fd's>
       int fd = open("/dev/tty1", O_RDWR);
       dup(fd);
       dup(fd);
       execvp("name", argv);
  }

Итак, stdin, out и err - все дубликаты одного и того же дескриптора файла, открытые для чтения и записи.

Ответ 2

read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

Должен работать. Обратите внимание: stdout меня будет отличным местом от stdin (даже в командной строке). Вы можете подавать выходные данные из другого процесса как stdin в ваш процесс или упорядочить stdin/stdout как файлы.

fprintf/fgets имеют буфер, что уменьшает количество системных вызовов.

Ответ 3

Лучшее предположение - stdin указывает на то, откуда поступает вход, ваш терминал и stdout указывают на то, куда должен идти выход, ваш терминал. Поскольку оба они указывают на одно и то же место, они взаимозаменяемы (в данном случае)?

Ответ 4

Если вы запустите программу в UNIX

myapp < input > output

Вы можете открыть /proc/ {pid}/fd/1 и прочитать из него, открыть /proc/ {pid}/fd/0 и записать на него и, например, скопировать output в input. (Возможно, есть более простой способ сделать это, но я знаю, что это работает)

Вы можете делать любые вещи, которые просто путают, если вы вкладываете свой ум в это.;)

Ответ 5

Очень возможно, что дескрипторы файлов 0, 1 и 2 открыты для чтения и записи (и на самом деле все они относятся к одному и тому же базовому "открытому описанию файла" ), и в этом случае то, что вы делаете будет работать. Но, насколько я знаю, нет никакой гарантии, так что это тоже может не сработать. Я действительно верю, что POSIX где-то указывает, что если stderr подключен к терминалу, когда программа вызывается оболочкой, он должен быть доступен для чтения и записи, но я не могу найти ссылку сразу.

В общем, я бы рекомендовал против чтения из stdout или stderr, если вы не хотите, чтобы терминал считывал пароль, а stdin был перенаправлен (а не tty). И я бы рекомендовал никогда не писать в stdin - это опасно, и вы могли бы в конечном итоге сгладить файл, который пользователь не ожидал записать!

Ответ 6

Если вы хотите написать сообщение в stdin, вы можете открыть текущий tty и вызвать системный вызов write для записи сообщения в этот fd:

string console_cmd = "hello";
string tty = ttyname(STDIN_FILENO);
int fd = open(tty.c_str(), O_WRONLY);
write(fd, console_cmd.c_str(), console_cmd.size());

Аналогично, прочитайте из stdout.