Zeilenweises einlesen einer dynamisch wachsenden Datei
-
Hallo liebe Community
Ich habe ein Problem, das etwas tricky zu lösen sein wird, jedoch hoffe ich, dass ihr mir helfen könnt.
Ich erkläre kurz den Kontext:
Ich habe ein Programm, welches unter Linux eine Nmap-Ausgabe in ein File output.txt macht und diese anschließend Parsed um die einzelnen Hosts, die Nmap im Netzwerk findet in eine von mir definierte linked List aufnimmt/einfügt.
Jetzt ist es so, dass diese Nmap-Aufrufe teilweise sehr lange (bis zu 30/45 Minuten laufen. Aus diesem Grund suchte ich eine Möglichkeit die Fortschrittsanzeige des Scans anzeigen zu lassen. Das hat funktioniert.
Nun bringt es mir aber leider nichts, da diese Ausgabe des Fortschritts, die jede Sekunde ausgegeben wird mit dem gesamten Inhalt erst nach Ende des Scans von meinem Programm geparsed wird.
Daraufhin bin ich soweit gegangen mit fork() den system() aufruf mit dem nmap-Befehl in ein Kindprozess auszulagern.
Jetzt benötige ich allerdings HILFE DABEI, DIE OUTPUT.TXT DATEI IN ECHTZEIT AUSZULESEN, da ich nur dann die Daten des Fortschritts des gesamt-Scans dem Anwender des Tools direkt zur Verfügung stellen kann.Bitte, falls ich zu unklar formuliere, fragt nach!
Ich hoffe mir kann jemand helfenLiebe Grüße,
Felix
-
Hat dir der Tipp von Wutz aus dem anderen Thread geholfen?
-
Geht so, also ich habe probiert mich selbst über das Thema Pipes zu belesen und auch in Galileo Computing http://openbook.galileocomputing.de/linux_unix_programmierung/Kap09-002.htm#RxxKap09002040002D51F049100 gelesen und probiert das zu verstehen, jedoch ist mir das hinsichtlich meines Problems nicht klar wie mir das da helfen soll ...
und wie ich das da anwenden soll .. also bis jetzt habe ich versucht mit fork() in einem Kindprozess den system()-Aufruf von nmap zu machen und diesen in xml Format in eine text-Datei ausgeben zu lassen und im Elternprozess parallel dazu diese Datei auszulesen, jedoch checkt getline() nicht, dass es die letzte Zeile nicht wiederholen soll solange ncihts neues kommt sondern einfach warten.Ich würde das mit den Pipes echt gerne verstehen und auch anwenden können, jedoch finde ich nichts dazu , wobei ich konkret auf meine Situation zugeschnitten einen Lösungsansatz sehe.
Ich versuche mal konkretere Fragen Richtung Problemlösung zu stellen:
- Wie kann ich Zeilenweise aus einer Pipe auslesen?
- Wie kann ich (wer kennt Nmap gut?) Nmaps XML-Ausgabe statt in den anzugebenden Datei-Namen in eine Pipe schreiben lassen?
- Wie kann ich das Zeilenweise auslesen aus der Pipe in Echtzeit in meinen Eltern-Prozess verarbeiten?Ich hoffe das hat etwas meine Situation erklärt.
Liebe Grüße & Danke schonmal!
Felix
-
Ich habe gerade nur wenig Zeit:
- Halte dich von allem fern, wo der Galileo-Verlag seine Finger drin hat! Vergiss alles, was du je aus dessen Büchern oder Tutorials gelernt hast!
- Was du vor hast ist alles kein Problem, die Standardausgabe (also das, wo die ganzen Funktionen wirklich hinschreiben, von denen du vermutlich denkst, sie würden auf die Konsole/Bildschirm schreiben) des einen Prozesses wird zur Standardeingabe (also das, wo die ganzen Funktionen wirklich her lesen, von denen du vermutlich denkst, sie würden von der Konsole/Tastatur lesen) des anderen Prozesses. Das heißt, du kannst nach wie vor genau so lesen und schreiben, wie du es gewohnt bist. Ich nehme mal an, zeilenweises Lesen bekommst du in "normalen" Programmen hin, oder? Dann geht es genau so von einer Pipe.
-
jedoch checkt getline() nicht, dass es die letzte Zeile nicht wiederholen soll solange ncihts neues kommt sondern einfach warten.
getline? Machst du C++?
Letzte Zeile wiederholt sich? Das klingt, als hättest du deine Leseschleifen aus einem Buch vom Galileoverlag gelernt . Ich wette, du hast so etwas wie:while(!quelle.eof()) { getline(quelle, zeile); ausgabe << zeile; }
Liege ich damit richtig? Wenn ja: Das ist Schrott. Hol dir vernünftiges Lehrmaterial, dessen Autoren wenigstens ein Minimum der Sprache beherrschen, über die sie schreiben. Die oben gezeigte Leselogik wäre in C (und fast allen anderen gängigen Sprachen) übrigens genau so falsch.
-
Kurz zu dem getline(): Das ist kein Ansi C, aber in eine C-Library gepackt worden (denke vlt ist das von c++ portiert worden ..?)
http://openbook.galileocomputing.de/c_von_a_bis_z/016_c_ein_ausgabe_funktionen_016.htm#t2t34Und das funktioniert auch gut eigentlich.
Nein ich mache sonst doch nur C.Also Zeilenweises einlesen so ist kein Problem, solange das halt keine Datei ist, die dynamisch wächst nach unten hin.
Das ist mein Schleifenkopf, da in diese Tag-Kombi nur bei ende der Nmap Ausgabe vorkommt. (Ist wahrscheinlich absoluter Schrott wenn man XML Format hat dann normal nach Stringfolgen zu Parsen oder? Naja .. Anfänger halt .. Ich habe sonst C ausschließlich für Microcontroller-Technik gelernt und das ist irgendwei ne ganz schön andere Richtung)
while(getline(&ptline_in, &istorage, ptoutput) != 0 && strstr(ptline_in, "<runstats><finished" != 0))
Und Parallel dazu schreibt der Childprozess halt die xml datei und für das getline ist das INPUT_FILE ptoutput ein
File *ptoutput = open("output.txt");
Die Ausgabedatei wächst also und getline liest und liest und liest auch wenn nmap noch gar keine witere ausgabe getätigt hat. Das macht sich dann nämlich in den Datensätzen bemerkbar die in Linked Lists während der while-schleife gespeichert werden. da stehen dann leere werte drin. und das immer nachdem Nmap wieder so eine pause mit der Ausgabe macht, da das ja immer seine Scans in Päckchen von X Hosts pro scan packt. Hier sinds immer 4096 pro pack.
Welche Lese-Logik wäre denn stattdessen korrekt? Dasselbe nur mit Byte-Angabe statt Zeilen?
(Ich gebe das auch nicht direkt aus, sondern speichere da einzelne Teilstrings ab die ich mit strtok() raushole.)UPDATE: Also rausgefunden hab ich schon wie die Nmap XML Ausgabe auf stdout gelenkt wird anstatt auf den von Nmap gewünschten Dateinamen.
Einfach -oX - anstatt -oX output.x
-
Liege ich damit richtig? Wenn ja: Das ist Schrott. Hol dir vernünftiges Lehrmaterial, dessen Autoren wenigstens ein Minimum der Sprache beherrschen, über die sie schreiben. Die oben gezeigte Leselogik wäre in C (und fast allen anderen gängigen Sprachen) übrigens genau so falsch.
Das gehört zwar jetzt wieder nicht in diesen Thread, aber hilft ja nicht... Wei würde man es dann "Richtig" machen? Einlesen bis EOF hört sich doch nicht sooo falsch an??
-
new_2211 schrieb:
Liege ich damit richtig? Wenn ja: Das ist Schrott. Hol dir vernünftiges Lehrmaterial, dessen Autoren wenigstens ein Minimum der Sprache beherrschen, über die sie schreiben. Die oben gezeigte Leselogik wäre in C (und fast allen anderen gängigen Sprachen) übrigens genau so falsch.
Das gehört zwar jetzt wieder nicht in diesen Thread, aber hilft ja nicht... Wei würde man es dann "Richtig" machen? Einlesen bis EOF hört sich doch nicht sooo falsch an??
Ich kann mir auch grade nicht vorstellen wie es anders gehen soll ..
Wobei das EOF doch End Of File ist oder?
und ich hab ja gesagt dass bei meinem Fall die Datei nach und nach wächst und ich eigentlich mit dem auslesen solange waren will bis eine bestimmte Zeile kommt und nicht bis das ende der Datei kommt. weil nach 1 Sekunde ist das ende der Datei was ganz anderes als nach 5 Sekunden ... also jetzt in meinem Fall .. Falls du das meintest ..?LG
Felix
-
new_2211 schrieb:
Liege ich damit richtig? Wenn ja: Das ist Schrott. Hol dir vernünftiges Lehrmaterial, dessen Autoren wenigstens ein Minimum der Sprache beherrschen, über die sie schreiben. Die oben gezeigte Leselogik wäre in C (und fast allen anderen gängigen Sprachen) übrigens genau so falsch.
Das gehört zwar jetzt wieder nicht in diesen Thread, aber hilft ja nicht... Wei würde man es dann "Richtig" machen? Einlesen bis EOF hört sich doch nicht sooo falsch an??
Hatte nicht genug Zeit und die Frage ist 1000 Mal im Forum beantwortet worden und steht in jedem guten(!) Buch*. Wann wird das eof-Flag gesetzt? Nachdem über das Ende gelesen wurde. So wie auch jedes andere Fehlerflag (warum werden die hier eigentlich nicht geprüft?) logischerweise erst gesetzt werden kann, nachdem der Fehler passiert ist. Gerade hier sollte das doch einleuchtend sein, da im Vorhinein gar nicht fest steht, ob überhaupt noch Daten kommen (geschweige denn, ob überhaupt ein weiterer Leseversuch erfolgen würde). Nun kann man sich gerne mal ausmalen, was wohl passiert, wenn die Leseaktion mangels Daten fehlschlägt, man das (falsche!) Ergebnis aber trotzdem ungeprüft ausgibt. Dann bekommt man das, was der Threadersteller beschreibt.
Lesefunktionen haben Rückgabewerte. Man benutze sie!while(erfolgsprüfung(leseaktion(quelle, daten))) { verarbeite(daten); }
So sieht eine typische Leselogik aus. Und bei der Erfolgsprüfung teste man besser nicht nur auf eof, sondern auf alle Fehler. Dies ist in der Regel sogar einfacher, als speziell nur auf eof zu testen.
*: Es ist auch ein typisches Alarmzeichen für ein schlechtes Buch, wenn es anders ist. Ohne es gesehen zu haben, wette ich, dass die Galileo-Quelle es falsch erklärt. Einfach aus Erfahrung über die sonstige Qualität dieses Verlages.
Und "Schlecht" wirklich in dem Sinne von "für den Abfalleimer". Wie soll man etwas aus einem Lehrbuch lernen, dessen Autor keine Ahnung von einfachsten Abläufen hat? Da lernt man nur dessen Fehler. Daher: Finger weg!
-
Dann würde mir zum Einlesen nur einfallen, den Dateizeiger auf´s Ende zu bewegen, mit ftell die "Position" zu merken, und dann genau diese Anzahl an Zeichen einzulesen.
Aber selbst habe ich es immer mit EOF gemacht. Die meisten Quellen, machen es glaub ich auch so, bin mir nicht 100% sicher, aber ich glaube auch im K&R ein Beispiel mit While !EOF gesehen zu haben...
-
while ((c = getchar()) != EOF)
entspricht
while(erfolgsprüfung(leseaktion(quelle, daten)))
Außerdem kann
EOF
nicht mit jeder I/O-Funktion verwendet werden. Zum Beispiel nicht beifgets
(NULL
) oderfprintf
(negativesint
).
-
new_2211 schrieb:
Die meisten Quellen, machen es glaub ich auch so, bin mir nicht 100% sicher, aber ich glaube auch im K&R ein Beispiel mit While !EOF gesehen zu haben...
Die meisten Quellen: weiss nicht. K&R: nein (jedenfalls nicht in meiner Kopie).
Aber ohne Frage: viele Quellen machen diesen Fehler.Das Ding ist ein richtiger Ressourcenfresser.
Ich möchte nicht wissen, wieviele User SeppJ schon darauf hinweisen musste. Ich bin mir auch sicher, dass er schon Textbausteine dafür angelegt hat.
Allein: es ist sicherlich nachhaltiger, wenn er auf jeden, der diesen Fehler macht, individuell eingeht.Aber nochmal zum K&R.
Da sind zwei Beispiele:double sum, v; sum = 0; while (scanf("%lf", &v) == 1) printf("\t%.2f\n", sum += v);
while (getline(line, sizeof(line)) > 0) { if (sscanf(line, "%d %s %d", &day, monthname, &year) == 3) printf("valid: %s\n", line); /* 25 Dec 1988 form */ else if (sscanf(line, "%d/%d/%d", &month, &day, &year) == 3) printf("valid: %s\n", line); /* mm/dd/yy form */ else printf("invalid: %s\n", line); /* invalid form */ }
Oha: wie SeppJ gesagt hat: beide werten die Rückgabe der Einlesefunktion aus. (Das
getline()
im zweiten Beispiel wird vorher im Buch definiert - macht aber nix, was man nicht erwarten würde).
Das Pattern, wie es EinGast geschrieben hat kommt auch vor. Aber beigetc()
fgetc()
undgetchar()
prüft man - wie angemerkt - auf EOF, weil EOF die Rückgabe im Fehlerfall ist.Im C Standard ist tatsächlich ein Beispiel wie folgt:
#include <stdio.h> /* ... */ int count; float quant; char units[21], item[21]; do { count = fscanf(stdin, "%f%20s of %20s", &quant, units, item); fscanf(stdin,"%*[^\n]"); } while (!feof(stdin) && !ferror(stdin));
Aber das soll einen anderen Sachverhalt illustrieren (die unterschiedlichen Werte von
quant
,units
,item
undcount
bei einer definierten Eingabe.)
-
Furble Wurble schrieb:
Im C Standard ist tatsächlich ein Beispiel wie folgt:
#include <stdio.h> /* ... */ int count; float quant; char units[21], item[21]; do { count = fscanf(stdin, "%f%20s of %20s", &quant, units, item); fscanf(stdin,"%*[^\n]"); } while (!feof(stdin) && !ferror(stdin));
Aber das soll einen anderen Sachverhalt illustrieren (die unterschiedlichen Werte von
quant
,units
,item
undcount
bei einer definierten Eingabe.)Auch diese Schleife ist vollkommen richtig. Es muss nicht unbedingt while sein. Die Logik ist hier jedenfalls korrekt.
-
Sourcecode von tail besorgen (Open source) und nachschauen, was bei tail -f datei gemacht wird.
Ich hab auch sowas mal gebaut - bei eof Position merken Close, Reopen und ab da weiterlesen (mit kleinm sleep wegen Dauerlast).