передать stdout fd в системный вызов ‘read’, но он все равно работает нормально

Я передаю 1 (stdout) / 2 (stderr) для read системного вызова, но он все еще работает нормально. Затем я передаю 0 (stdin), чтобы write системный вызов, и выясняю, что он тоже работает!

 int main(int argc, char** argv){ char buf[1024] = "abcdefghi\n"; write(0, buf, 10); char readbuf[1024] = {0}; // read(1, readbuf, 10); works too read(2, readbuf, 10); write(2, readbuf, 10); return 0; } 

выход:

 abcdefghi hey stdin <-- I input this hey stdin 

Смущенный, я думал, что это должно быть ошибкой.

Experiement:

Затем я попытался перенаправить FD 2.

 $ ./a.out 2>/dev/null 

на этот раз и чтение, и вторая запись не «видны». Выход

 abcdefgi 

Таким образом, stderr можно использовать для чтения?

Затем я закрываю stdout & stderr и делаю две копии stdin:

 int main(int argc, char** argv){ char buf[1024] = "abcdefghi\n"; close(1); close(2); dup2(0, 1); dup2(0, 2); write(0, buf, 10); char redbuf[1024] = {0}; read(2, redbuf, 10); write(2, redbuf, 10); return 0; } 

Опять это работает.

выход:

 abcdefghi hey stdin <-- I input this hey stdin 

Так что stdin можно использовать для записи?

Мне нужно некоторое объяснение здесь.

Вопрос

Я хочу знать:

Почему stdout / stderr можно использовать для чтения?

Почему стандартный ввод можно использовать для записи?

Является ли три streamа ( stdin, stdout, stderr ) внутренне одним streamом?

Если нет, то почему я получаю этот результат?

    2 Solutions collect form web for “передать stdout fd в системный вызов ‘read’, но он все равно работает нормально”

    Единственным условием является использование fd 0/1/2 для ввода / вывода / ошибки. Если вы вызываете программу без перенаправления, все три относятся к вашему tty, и ваш tty открыт с правами чтения и записи. Это означает, что вы можете читать или писать на них, как вы хотите. Вы можете назвать их одним и тем же streamом, хотя stream выражений часто используется для ввода-вывода более высокого уровня, такого как FILE в C или stream в C ++.

    Это причина того, что оба или не перенаправленные примеры просто повторяют введенный вами текст.

    С другой стороны, если вы сделаете redirect, shell откроет файлы только для чтения или только для записи. В вашем примере ./a.out 2>/dev/null запись в 0 по-прежнему подключена к терминалу, потому что она не перенаправлена, и поэтому отображается на экране. Чтение из 2 связано только с записью /dev/null и в этом случае должно произойти сбой, но вы не заметите отличий от вашей программы. Запись в 2 успешна, но записана в /dev/null . Недопустимое чтение и допустимая запись в /dev/null не отображаются на вашем терминале.

    Пока вы не перенаправили stdin / stdout / stderr, эти файловые дескрипторы были открыты процедурой входа в систему, и это открывает связанный tty для чтения и записи в качестве первого файла (в результате получается файловый дескриптор # 0) и позже вызывает dup() 2 раза, чтобы получить файловые дескрипторы для stdout и stderr.

    Как уже упоминалось в разделе «Как меньше» получает данные из стандартного ввода, все еще имея возможность читать команды от пользователя? в прежние времена (до появления /dev/tty в UNIX ) такие программы, как more , читали из stderr при запросе подтверждения.

    Linux и Unix - лучшая ОС в мире.