Запись на 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.