2017-03-22 3 views
0

Ich schreibe eine Anwendung, die zuerst Daten von einer Unix-Pipeline empfängt und dann den Benutzer zur Eingabe auffordert. Was ich nicht herausfinden kann, ist, warum die Eingabe aus der Pipeline nicht richtig zu schließen scheint, bevor der Benutzer zur Eingabe aufgefordert wird. Es fühlt sich an, als würde ich hier etwas sehr Elementares vermissen.C - Stdin, Unix-Pipeline und EOF

Ich habe alle Beispiele für Spülen stdin präsentiert here ohne Erfolg versucht. This scheint auch potenziell relevant, aber ich habe es nicht geschafft, relevante Antworten zu extrahieren.

#include <stdio.h> 
#include <stdlib.h> 

#define BUFSZ 1024 

int main(void) { 

    char *buf = calloc(BUFSZ, sizeof(char)); 

    while(fgets(buf, BUFSZ, stdin)) { printf("Pipe input: %s", buf); } 

    printf("Enter input: "); 
    fgets(buf, BUFSZ, stdin); 
    printf("User input: %s", buf); 

    free(buf); 
    return 0; 
} 

Beispiel der Verwendung und Ausgabe:

$ cat testdata2 | ./a.out 
Pipe input: testdata testdata 
Pipe input: testdata testdata2 
Pipe input: testdata testdata3 
Pipe input: testdata testdata4 
Pipe input: testdata testdata5 
Pipe input: testdata testdata6 
Pipe input: testdata testdata7 
Enter input: User input: testdata testdata7 
$ 

Wie kann es sein, dass die zweite fgets() (für die Tastatureingabe bestimmt) nie den Puffer berührt?

Dieser MCVE wurde unter OSX und Linux mit identischen Ergebnissen kompiliert getestet.

+0

sollten Sie 'calloc()' BUFSZ + 1 so haben Sie Platz für die '\ 0 ', wenn Sie jemals lange genug in einer Zeile gelesen, um diesen Puffer zu füllen. –

+2

Ihr Problem ist nicht, dass 'stdin' nicht geschlossen wird (es tut, weil' fgets' 'NULL' zurückgibt), sondern dass es nicht wieder für Benutzereingaben geöffnet wird. – Kninnug

+0

@ChrisTurner 'fgets' ermöglicht das: Sie sagen es nur die tatsächliche Puffergröße. –

Antwort

5

Wenn stdin eine Rohrleitung ist, dann ist stdin nicht das Terminal. Wenn du am Ende der Pfeife bist, war es das! Das ist das Ende von stdin. Sie erwarten eine Art magische Transformation, bei der stdin aufhört, die Pipe zu sein und etwas anderes zu sein. Erwarte das nicht. Es ist immer noch die Pfeife. Und EOF ist aufgetreten. Für Rohre ist EOF eine dauerhafte Bedingung. Sobald du EOF getroffen hast, wirst du nie mehr bekommen.

Überprüfen Sie den Rückgabewert von fgetsalle Zeit. Sie werden sehen, dass die letzte Null zurückgibt, weil sie bei EOF ist.

Programme, die Tastatureingabe lesen möchten verrohrt stdin und auch separat das Terminal öffnen bekommen müssen, wie in FILE *tty = fopen("/dev/tty", "r");

+0

Ah ja, das scheint tatsächlich die Lösung zu sein. Ich wusste, dass ich hier etwas Elementares vermisste. Vielen Dank! –