web-dev-qa-db-fra.com

Écrire sur stdin et lire à partir de stdout (programmation UNIX/LINUX/C)

Je travaillais sur une tâche dans laquelle un programme prenait un descripteur de fichier comme argument (généralement du parent dans un appel exec) et lisait dans un fichier et écrivait dans un descripteur de fichier. de la ligne de commande et ne pas donner une erreur si j'ai utilisé 0, 1 ou 2 comme descripteur de fichier. Cela me paraissait logique, sauf que je pouvais écrire sur stdin et le montrer à l’écran.

Y a-t-il une explication à cela? J'ai toujours pensé qu'il y avait une certaine protection sur stdin/stdout et vous ne pouvez certainement pas utiliser fprintf pour stdin ou fgets depuis 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;
}
14
Tim

Si vous tentez d'écrire sur un fichier marqué en lecture seule ou inversement, write et read renverront -1 et échoueront. Dans ce spécifique cas, stdin et stdout sont en fait le même fichier. Essentiellement, avant que votre programme ne soit exécuté (si vous ne faites aucune redirection), le shell va:

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

Ainsi, stdin, out et err sont tous des doublons du même descripteur de fichier, ouverts en lecture et en écriture.

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

Devrait marcher. Remarque - stdout peut être différent de stdin (même sur la ligne de commande). Vous pouvez alimenter la sortie d'un autre processus en tant que stdin, ou organiser le stdin/stdout en tant que fichiers.

fprintf/fgets ont un tampon - réduisant ainsi le nombre d'appels système.

2
Ed Heal

Il est préférable de deviner - stdin indique l’origine de l’entrée, votre terminal et stdout l’emplacement de la sortie, votre terminal. Puisqu'ils pointent tous deux au même endroit, ils sont interchangeables (dans ce cas)?

1
Avery3R

Si vous exécutez un programme sous UNIX

myapp < input > output

Vous pouvez ouvrir/proc/{pid}/fd/1 et en lire, ouvrir/proc/{pid}/fd/0 et y écrire et copier, par exemple, output dans input. (Il existe peut-être un moyen plus simple de le faire, mais je sais que cela fonctionne)

Vous pouvez faire toute sorte de choses qui déroutent si vous y réfléchissez. ;)

1
Peter Lawrey

Si vous souhaitez écrire un message dans stdin, vous pouvez ouvrir le terminal en cours et appeler l'appel système write pour écrire le message dans ce 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());

De même, lisez sur stdout.

0
vinllen

Il est très possible que les descripteurs de fichier 0, 1 et 2 soient tous ouverts en lecture et en écriture (et qu'ils se réfèrent tous à la même "description de fichier ouvert" sous-jacente), auquel cas ce que vous ferez fonctionnera. Mais pour autant que je sache, il n'y a aucune garantie, donc cela pourrait également ne pas fonctionner. Je pense que POSIX précise quelque part que si stderr est connecté au terminal lorsqu'un programme est appelé par le shell, il est censé être lisible et inscriptible, mais je ne trouve pas la référence tout de suite.

En général, je déconseille de lire depuis stdout ou stderr sauf si vous cherchez un terminal pour lire un mot de passe, et que stdin a été redirigé (pas un tty). Et je vous recommanderais de ne jamais écrire sur stdin - c'est dangereux et vous risqueriez de surcharger un fichier que l'utilisateur ne s'attendait pas à écrire!

0
R..