web-dev-qa-db-fra.com

Rediriger la sortie de l'exec vers un tampon ou un fichier

J'écris un programme C où je fork(), exec() et wait(). Je voudrais prendre la sortie du programme que j'ai exécuté pour l'écrire dans un fichier ou un tampon.

Par exemple, si j'exécute ls je veux écrire file1 file2 etc dans le tampon/fichier. Je ne pense pas qu'il existe un moyen de lire stdout, donc cela signifie-t-il que je dois utiliser un tuyau? Y a-t-il ici une procédure générale que je n'ai pas pu trouver?

38
devin

Pour envoyer la sortie vers un autre fichier (je laisse de côté la vérification des erreurs pour me concentrer sur les détails importants):

if (fork() == 0)
{
    // child
    int fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    dup2(fd, 1);   // make stdout go to file
    dup2(fd, 2);   // make stderr go to file - you may choose to not do this
                   // or perhaps send stderr to another file

    close(fd);     // fd no longer needed - the dup'ed handles are sufficient

    exec(...);
}

Pour envoyer la sortie vers un tube afin que vous puissiez ensuite lire la sortie dans un tampon:

int pipefd[2];
pipe(pipefd);

if (fork() == 0)
{
    close(pipefd[0]);    // close reading end in the child

    dup2(pipefd[1], 1);  // send stdout to the pipe
    dup2(pipefd[1], 2);  // send stderr to the pipe

    close(pipefd[1]);    // this descriptor is no longer needed

    exec(...);
}
else
{
    // parent

    char buffer[1024];

    close(pipefd[1]);  // close the write end of the pipe in the parent

    while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
    {
    }
}
80

Vous devez décider exactement ce que vous voulez faire - et de préférence l'expliquer un peu plus clairement.

Option 1: fichier

Si vous savez dans quel fichier vous voulez que la sortie de la commande exécutée aille, alors:

  1. Assurez-vous que le parent et l'enfant conviennent du nom (le parent décide du nom avant de bifurquer).
  2. Fourches parents - vous avez deux processus.
  3. L'enfant réorganise les choses de sorte que le descripteur de fichier 1 (sortie standard) passe au fichier.
  4. Habituellement, vous pouvez laisser l'erreur standard seule; vous pouvez rediriger l'entrée standard depuis/dev/null.
  5. L'enfant exécute ensuite la commande appropriée; ladite commande s'exécute et toute sortie standard va dans le fichier (il s'agit de la redirection de base des E/S Shell).
  6. Le processus exécuté se termine alors.
  7. Pendant ce temps, le processus parent peut adopter l'une des deux stratégies principales:
    • Ouvrez le fichier en lecture et continuez à lire jusqu'à ce qu'il atteigne un EOF. Il doit ensuite vérifier si l'enfant est décédé (donc il n'y aura plus de données à lire), ou attendre d'attendre plus d'informations de l'enfant.
    • Attendez que l'enfant meure, puis ouvrez le fichier pour lecture.
    • L'avantage de la première est que le parent peut faire une partie de son travail pendant que l'enfant court aussi; l'avantage de la seconde est que vous n'avez pas à vous débrouiller avec le système d'E/S (lecture répétée après EOF).

Option 2: tuyau

Si vous souhaitez que le parent lise la sortie de l'enfant, faites en sorte que l'enfant redirige sa sortie vers le parent.

  1. Utilisez popen () pour le faire facilement. Il exécutera le processus et enverra la sortie à votre processus parent. Notez que le parent doit être actif pendant que l'enfant génère la sortie car les canaux ont une petite taille de tampon (souvent 4-5 Ko) et si l'enfant génère plus de données que pendant que le parent ne lit pas, l'enfant bloquera jusqu'à ce que le lit le parent. Si le parent attend la mort de l'enfant, vous êtes dans une impasse.
  2. Utilisez pipe () etc. pour le faire à la dure. Le parent appelle pipe (), puis bifurque. L'enfant trie la plomberie de sorte que l'extrémité d'écriture du tuyau soit sa sortie standard et s'assure que tous les autres descripteurs de fichier relatifs au tuyau sont fermés. Cela pourrait bien utiliser l'appel système dup2 (). Il exécute ensuite le processus requis, qui envoie sa sortie standard dans le tuyau.
  3. Pendant ce temps, le parent ferme également les extrémités indésirables du tuyau, puis commence à lire. Lorsqu'il obtient EOF sur le tuyau, il sait que l'enfant a terminé et fermé le tuyau; il peut également fermer son extrémité.
14
Jonathan Leffler

Puisque vous semblez que vous allez utiliser ceci dans un environnement linux/cygwin, vous voulez utiliser popen . C'est comme ouvrir un fichier, seulement vous obtiendrez les programmes d'exécution stdout, vous pouvez donc utiliser votre fscanf, fread etc. normal.

2
Blindy

Après la fourche, utilisez dup2(2) pour dupliquer le FD du fichier dans le FD de stdout, puis exécutez.