Umleitung der Exec-Ausgabe in einen Puffer oder eine Datei

Lesezeit: 5 Minuten

devins Benutzeravatar
devin

Ich schreibe ein C-Programm, wo ich fork(), exec()und wait(). Ich möchte die Ausgabe des Programms, das ich ausgeführt habe, nehmen, um es in eine Datei oder einen Puffer zu schreiben.

Wenn ich zum Beispiel exec ls Ich möchte schreiben file1 file2 etc zwischenspeichern/archivieren. Ich glaube nicht, dass es eine Möglichkeit gibt, stdout zu lesen. Bedeutet das, dass ich eine Pipe verwenden muss? Gibt es hier ein allgemeines Verfahren, das ich nicht finden konnte?

Benutzeravatar von R Samuel Klatchko
R. Samuel Klatschko

Zum Senden der Ausgabe an eine andere Datei (ich lasse die Fehlerprüfung aus, um mich auf die wichtigen Details zu konzentrieren):

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(...);
}

Um die Ausgabe an eine Pipe zu senden, können Sie die Ausgabe dann in einen Puffer einlesen:

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)
    {
    }
}

  • Sie schreiben: “close(pipefd[1]); // dieser Deskriptor wird nicht mehr benötigt”. Warum?

    – hoffmaje

    9. Dezember 2012 um 7:46 Uhr


  • Was bedeutet die ‘1’ in der Zeile, in der Sie den Dateideskriptor duplizieren und die Standardausgabe an die Datei senden? Ich kann keine Dokumentation dazu finden.

    – Matthäus Brzezinski

    12. Februar 2016 um 3:34 Uhr

  • @MattBrzezinski – 1 ist der Dateideskriptor für stdout.

    – R. Samuel Klatschko

    13. Februar 2016 um 5:13 Uhr

  • Es wäre ausgezeichnet, wenn Sie Ihre Antwort erweitern und erklären könnten, wie man stdout & stderr separat liest, dh wie man aus zwei Pipes liest. Ich nehme an, dies würde die Verwendung beinhalten select stattdessen und schließlich a waitpid auf das Kind, um den Zombie zu entfernen?

    – Frerich Raabe

    7. März 2016 um 9:21 Uhr

  • bottomuppcs.com/file_descriptors.xhtml (gefunden durch googeln Standard-Dateideskriptornummern)

    Benutzer3458

    12. Juni 2018 um 20:03 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Sie müssen genau entscheiden, was Sie tun möchten – und es am besten etwas klarer erklären.

Option 1: Datei

Wenn Sie wissen, in welche Datei die Ausgabe des ausgeführten Befehls gehen soll, dann:

  1. Stellen Sie sicher, dass sich Elternteil und Kind auf den Namen einigen (Elternteil entscheidet den Namen vor dem Forking).
  2. Parent Forks – Sie haben zwei Prozesse.
  3. Child reorganisiert die Dinge so, dass Dateideskriptor 1 (Standardausgabe) in die Datei geht.
  4. Normalerweise können Sie den Standardfehler in Ruhe lassen; Sie könnten die Standardeingabe von /dev/null umleiten.
  5. Das Kind führt dann den relevanten Befehl aus; besagter Befehl wird ausgeführt und alle Standardausgaben gehen in die Datei (dies ist die grundlegende Shell-E/A-Umleitung).
  6. Der ausgeführte Prozess wird dann beendet.
  7. In der Zwischenzeit kann der übergeordnete Prozess eine von zwei Hauptstrategien anwenden:
    • Öffnen Sie die Datei zum Lesen und lesen Sie weiter, bis sie ein EOF erreicht. Es muss dann noch einmal prüfen, ob das Kind gestorben ist (also keine weiteren Daten zum Lesen vorhanden sind) oder herumhängen und auf weitere Eingaben des Kindes warten.
    • Warten Sie, bis das Kind gestorben ist, und öffnen Sie dann die Datei zum Lesen.
    • Der Vorteil des ersten ist, dass der Elternteil einen Teil seiner Arbeit erledigen kann, während das Kind ebenfalls läuft; der Vorteil des zweiten ist, dass Sie sich nicht mit dem E/A-System herumschlagen müssen (wiederholtes Lesen über EOF hinaus).

Option 2: Rohr

Wenn Sie möchten, dass der Elternteil die Ausgabe des Kinds liest, sorgen Sie dafür, dass das Kind seine Ausgabe an den Elternteil zurückleitet.

  1. Verwenden Sie popen(), um dies auf einfache Weise zu tun. Es führt den Prozess aus und sendet die Ausgabe an Ihren übergeordneten Prozess. Beachten Sie, dass das Elternteil aktiv sein muss, während das Kind die Ausgabe generiert, da Pipes eine kleine Puffergröße haben (häufig 4-5 KB) und wenn das Kind mehr Daten generiert, während das Elternteil nicht liest, blockiert das Kind bis zum Eltern lesen. Wenn der Elternteil darauf wartet, dass das Kind stirbt, haben Sie einen Deadlock.
  2. Verwenden Sie pipe() etc, um dies auf die harte Tour zu tun. Parent ruft pipe() auf und verzweigt sich dann. Das Kind sortiert die Leitungen so, dass das Schreibende der Pipe seine Standardausgabe ist, und stellt sicher, dass alle anderen Dateideskriptoren, die sich auf die Pipe beziehen, geschlossen sind. Dies könnte durchaus den Systemaufruf dup2() verwenden. Es führt dann den erforderlichen Prozess aus, der seine Standardausgabe durch die Pipe sendet.
  3. In der Zwischenzeit schließt der Elternteil auch die unerwünschten Enden der Pfeife und beginnt dann zu lesen. Wenn es EOF auf der Pfeife erhält, weiß es, dass das Kind fertig ist und die Pfeife geschlossen hat; es kann auch sein Ende des Rohrs schließen.

Da Sie so aussehen, als würden Sie dies in einer Linux/Cygwin-Umgebung verwenden, möchten Sie verwenden Popen. Es ist wie das Öffnen einer Datei, nur dass Sie die ausgeführten Programme erhalten stdoutdamit Sie Ihre normale verwenden können fscanf, fread usw.

Nach dem Forken verwenden dup2(2) um das FD der Datei in das FD von stdout zu duplizieren, dann exec.

Du könntest auch Linux verwenden sh Befehl und übergeben Sie ihm einen Befehl, der die Umleitung enthält:

string cmd = "/bin/ls > " + filepath;

execl("/bin/sh", "sh", "-c", cmd.c_str(), 0);

1410190cookie-checkUmleitung der Exec-Ausgabe in einen Puffer oder eine Datei

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy