Запись в stdin и чтение из stdout (Программирование в UNIX / LINUX / C) - PullRequest
15 голосов
/ 12 сентября 2011

Я работал над заданием, в котором программа взяла дескриптор файла в качестве аргумента (обычно от родителя при вызове 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;
}

Ответы [ 6 ]

12 голосов
/ 07 октября 2011

Попытка записи в файл, помеченный только для чтения, или наоборот, приведет к тому, что 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 голосов
/ 12 сентября 2011
read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

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

fprintf / fgets имеет буфер - тем самым сокращая количество системных вызовов.

1 голос
/ 12 сентября 2011

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

myapp < input > output

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

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

1 голос
/ 12 сентября 2011

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

0 голосов
/ 16 августа 2016

Если вы хотите записать сообщение в стандартный ввод, вы можете открыть текущий 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());

Аналогично, читать из стандартного вывода.

0 голосов
/ 12 сентября 2011

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

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

...