tail -f beenden in einer Pipe [Geloest]

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
heinz
Beiträge: 318
Registriert: 20.12.2007 01:43:49

tail -f beenden in einer Pipe [Geloest]

Beitrag von heinz » 11.02.2019 16:25:10

Hallo Zusammen,

ich moechte in einem C-Programm mathematische Formeln berechnen lassen die zur Laufzeit in dem C-Programm eingegeben werden koennen.
Um mir die Arbeit zu ersparen einen Parser zu schreiben, kam ich auf die Idee einfach BC zu nutzen.

Also erstellte ich 2 fifos ein und aus und starte innerhalb des C-Programms BC mit:

Code: Alles auswählen

tail -f ./ein | bc -ql |tee ./aus' &
Jetzt kann ich die Formel in ein schreiben und das Ergebnis aus aus lesen.
Funktioniert soweit prima.

Das Problem ist das beenden.
Schreibe ich nach ein den befehl quit, beendet sich der BC aber das tail -f nicht.
Ich habe zwar in "man tail" die Option "--pid PID" entdeckt aber die hilft in diesem Fall nicht da ich die PID von BC zum Zeitpunkt des Starts von tail noch nicht ermitteln kann.

Hat jemand vlt. eine erhellende Idee fuer mich?

Viele Gruesse, heinz

PS.
Was passiert eigentlich mit Daten die man in einen fifo "speichert", wenn sie nicht "ausgelesen" werden? Werden die verworfen oder sammeln sie sich irgendwo an?
Zuletzt geändert von heinz am 14.02.2019 00:32:33, insgesamt 1-mal geändert.

TomL
Beiträge: 3728
Registriert: 24.07.2014 10:56:59

Re: tail -f beenden in einer Pipe

Beitrag von TomL » 11.02.2019 18:36:01

Ich glaube, das ist relativ einfach zu lösen. Ich würde das zunächst in ein Bash-Script verpacken. Im Script wird als erstes mit "touch" eine leere Ausgabe in /tmp erzeugt, tail -f wird auf die Ausgabe-Datei angesetzt, aber gleichzeitig mit der PID des Scripts ans Script "gehängt". Die BC-Ausgaben werden danach in die Ausgabe-Datei umgeleitet. Und wenn sich BC schließlich nach "quit" beendet, endet das Script und damit auch via gebundener PID tail. Der Ordnunghalber könnte nun auch noch die Ausgabe-Datei in /tmp gelöscht werden.
vg, Thomas

Benutzeravatar
heinz
Beiträge: 318
Registriert: 20.12.2007 01:43:49

Re: tail -f beenden in einer Pipe

Beitrag von heinz » 11.02.2019 19:14:03

Sorry, ich steh gerade etwas auf dem Schlauch...
Woher bekommt BC denn seine Eingabe?

Code: Alles auswählen

touch /tmp/ein

tail -f /tmp/ein --pid "$$" | bc -ql |tee ./aus' &
So geht es nicht. Nach dem "quit" kommt:
tail: /tmp/ein: Datei abgeschnitten
und tail laeuft weiter...

Auch werden die Dateien in /tmp nach einiger Laufzeit sehr gross. OK. man koennte sie ab und zu loeschen...

TomL
Beiträge: 3728
Registriert: 24.07.2014 10:56:59

Re: tail -f beenden in einer Pipe

Beitrag von TomL » 11.02.2019 19:36:34

Code: Alles auswählen

#!/bin/bash
TempFileName="/tmp/$(basename $0).$$"
touch $TempFileName
/usr/bin/xterm -geometry 25x10+10+10 -e "/usr/bin/tail $TempFileName -n 100 --sleep-interval=2 -f --pid=$$" &
/usr/bin/bc >$TempFileName
exit 0
Die Eingabe erfolgt in dem Fenster, in dem das Script gestartet wurde, die Ausgabe des Rechen-Ergebnisses erfolgt im kleinen xterm-Fenster. Gibts Du "quit" im Eingabe-Fenster ein, werden beide Fenster geschlossen.
vg, Thomas

Benutzeravatar
heinz
Beiträge: 318
Registriert: 20.12.2007 01:43:49

Re: tail -f beenden in einer Pipe

Beitrag von heinz » 11.02.2019 20:50:49

Ersmal Danke fuer Deine Geduld!

Das funktioniert natuerlich aber wie bekomme ich die Rechenaufgabe an den bc gesendet?
Ich meine, ohne eine Eingabe von Hand?
Den tail nutze ich in meinem urspruenglichen Beispiel, um die Eingaben/Formeln entgegen zu nehmen.

Habe das mal versucht:

Code: Alles auswählen

echo "10+10" >/proc/`pidof bc`/fd/0
echo "10+10" >/proc/`pidof terminal in dem das Script laeuft`/fd/0
beides ohne Erfolg...

Vlt. habe ich es auch schlecht erklaert. Ich versuchs nochmal.
Ich habe ein C-Programm, welches einen String z.B. "10 + 10" an ein fifo oder eine Datei "schickt".
Der bc "lauscht" dort die ganze Zeit, nimmt die Formeln entgegennehmen und berechnet sie.
Das Ergebnis von bc soll dann wieder in ein fifo oder eine Datei geschrieben werden, damit das C-Programm es sich dort abholen kann.
Die Formeln werden einmalig im C-Programm eingegeben und beim Ablaufen mehrere male, mit verschiedenen Werten, an bc "verschickt".

In der Konsole teste ich es so:
Vorbereitung:

Code: Alles auswählen

mkfifo ./ein
mkfifo ./aus
Terminal-Fenster 1 "BC-Start":

Code: Alles auswählen

tail -f ./ein |bc -ql >./aus
Terminal-Fenster 2 "Ausgabe anzeigen":

Code: Alles auswählen

tail -f ./aus
Terminal-Fenster 3 "Formeln schicken":

Code: Alles auswählen

echo "10+10" >./ein
Beenden:

Code: Alles auswählen

echo "quit" >./ein
Beim Senden von "quit" soll der tail -f in Terminal-Fenster 1 beendet werden.


Habe eben ueberlegt ein drittes fifo zu nutzen um bc zuerst starten zu koennen.
Aber fuer die Eingabe brauche ich dann ja ein weiteres tail, welches dann natuerlich auch wieder stehenbleibt...
So etwa... (Sinnlos)

Code: Alles auswählen

tail -f ./nocheinfifo | bc -ql  |tee ./aus' &
tail -f ./ein >./nocheinfifo --pid `pidof bc`
Gruss heinz

pferdefreund
Beiträge: 3270
Registriert: 26.02.2009 14:35:56

Re: tail -f beenden in einer Pipe

Beitrag von pferdefreund » 12.02.2019 09:57:58

machs doch wie bisher und - so du alleine am Rechner bist - in deinem C-Programm
system('killall tail') und gut ist. Wirst ja nicht während das rennt, noch weitere tails am Laufen haben. Und wenn doch, dann halt
das Programm als anderer User laufen lassen denn der killall als normaler User killt nur die eigenen - keine fremden Prozesse.
Ist zwar unsauber - ich weiß, system ('irgendwas') ist eigentlich böse - aber ich habe schon immer nach der Methode "keep it simple" gearbeitet.

TomL
Beiträge: 3728
Registriert: 24.07.2014 10:56:59

Re: tail -f beenden in einer Pipe

Beitrag von TomL » 12.02.2019 10:21:13

Sorry Heinz, trotz einmal drüber schlafen fällt mir nix dazu ein. Ich habe ja eigentlich Spass an der Lösung solcher Rätsel, einfach aus Sportsgeist, auch wenn ich nix davon habe... das hält wach... :roll: ... aber da komme ich nicht weiter.
vg, Thomas

Benutzeravatar
Meillo
Moderator
Beiträge: 5219
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: tail -f beenden in einer Pipe

Beitrag von Meillo » 12.02.2019 10:30:53

Das was du machen willst, ist das gleiche was eine Shell macht: Aufruf eines externen Programms mit Daten reinschieben und rauslesen. Dazu brauchst du weder temporaere Dateien noch FIFOs noch `tail -f', sondern du kannst das mittels pipe(2) machen. Die relevanten Systemcalls sind fork(2), exec(2), pipe(2), close(2), ...

Wie es geht, kannst du z.B. hier lernen: http://www.mathematik.uni-ulm.de/sai/ss ... -teil3.pdf (Teil dieser Vorlesung: https://www.uni-ulm.de/mawi/mawi-numeri ... ftware-ii/ )

Du brauchst zwei Pipes, eine zum Reinschreiben und eine zum Rauslesen. (Bei jeder von den Pipes kannst du nur ein Endenpaar nutzen.) Dann forkst du einen Prozess, schliesst die Pipeenden passend an (dup2(2), close(2)), und machst ein exec(2) auf dein bc(1)-Kommando. Wenn das erledigt ist, kannst du im Hauptprozess deine Aufgabe in die Pipe reinschreiben und die Loesung aus der anderen Pipe rauslesen.

heinz hat geschrieben: ↑ zum Beitrag ↑
11.02.2019 16:25:10
PS.
Was passiert eigentlich mit Daten die man in einen fifo "speichert", wenn sie nicht "ausgelesen" werden? Werden die verworfen oder sammeln sie sich irgendwo an?
Das steht im verlinkten PDF ganz am Anfang.


Soviel auf die Schnelle. Bei Bedarf kann ich dir auch nochmal detailliertere Fragen beantworten ... falls du dein Problem ueberhaupt auf diesem niedrigen Level loesen willst.
Use ed(1) once in a while!

TomL
Beiträge: 3728
Registriert: 24.07.2014 10:56:59

Re: tail -f beenden in einer Pipe

Beitrag von TomL » 12.02.2019 10:40:22

Hah... gerade wenn man gedacht hat, man kanns nicht, blitzt es auf einmal inner Birne.... *lol*.....
Das funktionierte jetzt gerade ... und sowohl eine Ausgabe via tail als auch die Weiterleitung an eine andere Pipe kann jetzt (wenn gewünscht) reingebastelt werden:

Code: Alles auswählen

thomas@thomaspc:/testbin
$ cat y

#!/bin/bash

[ ! -p ./pipe ] && mkfifo ./pipe

while true; do
    result=$(bc < pipe)

    [ -z "$result" ] && break
    echo "= $result"
done

rm ./pipe
exit 0
Ausgaben im ersten Terminal:

Code: Alles auswählen

thomas@thomaspc:/testbin
$ ./y
= 6
= 4
thomas@thomaspc:/testbin
$ 
Eingaben im zweiten Terminal:

Code: Alles auswählen

$ echo "2*3" > pipe
thomas@thomaspc:/testbin
$ echo "2+2" > pipe
thomas@thomaspc:/testbin
$ echo "quit" > pipe
thomas@thomaspc:/testbin
$ 
Ich bitte um Nachsicht, weil ich Rechenaufgaben gerade eben innerhalb meiner mathematischen Grenzen gewählt habe.... :wink:
vg, Thomas

Benutzeravatar
heinz
Beiträge: 318
Registriert: 20.12.2007 01:43:49

Re: tail -f beenden in einer Pipe

Beitrag von heinz » 14.02.2019 00:32:07

pferdefreund hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 09:57:58
system('killall tail') und gut ist. Wirst ja nicht während das rennt, noch weitere tails am Laufen haben.
Danke fuer Deinen Vorschlag aber da ich oft viele Programme und Scripte am laufen habe wenn ich am Rechner arbeite ist das
keine so gute Idee. Und extra einen anderen Benutzer zu verwenden ist auch suboptimal...
Meillo hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 10:30:53
...du kannst das mittels pipe(2) machen. Die relevanten Systemcalls sind fork(2), exec(2), pipe(2), close(2), ...
Danke fuer die ausfuehrliche Erklaerung und besonders fuer den Link auf das PDF!
Du hast natuerlich recht, so sieht die perfekte Loesung aus.
Mit Pipes in C hab ich mich noch nie beschaeftigt, deshab kam ich erst garnicht auf die Idee... Ich werde mich da mal einzuarbeiten.
Das wird wohl die entgueltige Loesung werden. :THX:
Meillo hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 10:30:53
Bei Bedarf kann ich dir auch nochmal detailliertere Fragen beantworten ...
Danke fuer das Angebot! Komme sicher darauf zurueck, falls ich nicht weiterkomme...
Meillo hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 10:30:53
falls du dein Problem ueberhaupt auf diesem niedrigen Level loesen willst.
Niedriger Level? Was meinst Du damit? Niedrig weil es die korrekte vorgehensweise unter C ist?
TomL hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 10:40:22
Das funktionierte jetzt gerade ...
Danke fuers weiter druebernachdenken...
Hab es mal getestet. Leider setzt es immer wieder mal aus zwischendurch...
Das bedeutet, das manche Berechnungen irgendwie verloren gehen. Das tritt auch auf wenn ich nach jedem Senden einer Formel warte bis das Ergebnis "ansteht"
Ich habe den verdacht das es daran liegen koennte, dass von >pipe< nicht dauerhaft gelesen wird und vom C-Programm die Formeln zu schnell kommen...
Rein als Script, laeuft es aber gut!
TomL hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 10:21:13
Ich habe ja eigentlich Spass an der Lösung solcher Rätsel, einfach aus Sportsgeist,
Kann ich sehr gut verstehen, geht mir auch oft so...
Nicht sauer sein, aber ich werde wohl den Vorschlag von Meillo umsetzen.
Trotzdem Danke fuer Deine kreative Loesung!


Setze jetzt erstmal auf Geloest...

Dankbare Gruesse, heinz

Benutzeravatar
Meillo
Moderator
Beiträge: 5219
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: tail -f beenden in einer Pipe

Beitrag von Meillo » 14.02.2019 08:28:37

heinz hat geschrieben: ↑ zum Beitrag ↑
14.02.2019 00:32:07
Meillo hat geschrieben: ↑ zum Beitrag ↑
12.02.2019 10:30:53
falls du dein Problem ueberhaupt auf diesem niedrigen Level loesen willst.
Niedriger Level? Was meinst Du damit? Niedrig weil es die korrekte vorgehensweise unter C ist?
Niedrig weil auf Systemcall-Ebene. Dort ist das Verhaeltnis von tatsaechlich funktionalem Code und Fehlerbehandlung am schlechtesten. Ausserdem muss man da viel Code schreiben um wenig zu erreichen. Alleine die Pipes aufzubauen, fork, exec ... das nimmt schnell zwei Bildschirmseiten in Anspruch. Das meine ich mit niedrigem Level. Das will man sich normalerweise ersparen.

TomL geht das Problem in der Shell an, was so ziemlich dem hoechsten Level entspricht. Dort bekommst du am meisten geschenkt, musst dich mit den Details kaum beschaeftigen. Dafuer kannst du nicht alles massschneidern.

Das ist eine Abwaegungssache. Wenn du was lernen willst, dann ist dies hier optimal: Setze es sowohl in Low-Level-C als auch mittels der Shell um, dann vergleiche die Ergebnisse. Bin gespannt zu welchen Erkenntnissen zu kommst. (Es gibt da keine binaeren Antworten, bloss verschiedene Betrachtungen der Situation.)

Pipe, fork, exec in C selber zu verwenden wird dein Verstaendnis von Unix verbessern, soviel ist sicher. (Eine der wertvollsten Uebungen die du machen kannst, ist eine Shell selber zu implementieren.)

Nun aber viel Vergnuegen. Ich bin gespannt, wie sich deine Arbeiten entwickeln. :THX:
Use ed(1) once in a while!

Benutzeravatar
heinz
Beiträge: 318
Registriert: 20.12.2007 01:43:49

Re: tail -f beenden in einer Pipe [Geloest]

Beitrag von heinz » 15.02.2019 21:01:57

Meillo hat geschrieben: ↑ zum Beitrag ↑
14.02.2019 08:28:37
Niedrig weil auf Systemcall-Ebene.
Danke fuer die Erklaerung!

Oh mann, worauf habe ich mich da eingelassen... ;-)

Ich versuche gerade mir das ganze aus den Manpages zu erschliessen. (Trotz mangelhaften Englischkenntnissen...)

Verstaendnissfrage zu fork und exec:
Mit dem Befehl >fork< erzeuge ich einen eigenstaendigen Kind-Prozess des Ursprungs-Progamms.
Das bedeutet, dass Programm wird komplett verdoppelt und beide befinden sich an der gleichen "Programmstelle".
Danach laufen beide Programm-Teile unabhaengig voneinander weiter.
Mit dem Befehl >execl< ersetze ich dann den Kind-Prozess oder das Ursprungs-Progamm durch z.B. bc.
Um den Kind-Prozess wieder zu beenden, lasse ich ihn einfach in ein exit laufen.
Ist das soweit korrekt?

Mit den Pipes habe ich im Moment etwas groessere Verstaendnissprobleme...
Mit:
int pipes[2];
pipe(pipes);
erzeuge ich vor dem fork zwei Pipes (Lesen und Schreiben).
Nach dem fork besitzen beide Prozesse die gleichen pipes.
Das bedeutet, ich muss in einem der Prozesse die beiden pipes vertauschen. (Lesen wird zu Schreiben und umgekehrt.)
Ist das auch korrekt?

Da beide Prozesse unabhaengig voneinander Laufen, woher wissen dann die Prozesse wer gerade "dran" ist?
Wenn z.B. der Prozess, der die Berechnung durchfuehrt, etwas langsamer laeuft als der Prozess, der die Formeln versendet...

Im Moment bin ich so weit, dass ich mittels >write< eine Formel an den Kind-Prozess senden kann und er mir dann das Ergebnis von bc in die Standardausgabe schreibt.

Habe gerade etwas Probleme den Wald zu sehen, da noch lauter Baeume davor stehen. Aber ich bleibe dran...

Gruss, heinz

Benutzeravatar
Meillo
Moderator
Beiträge: 5219
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: tail -f beenden in einer Pipe [Geloest]

Beitrag von Meillo » 15.02.2019 21:31:31

heinz hat geschrieben: ↑ zum Beitrag ↑
15.02.2019 21:01:57
Meillo hat geschrieben: ↑ zum Beitrag ↑
14.02.2019 08:28:37
Niedrig weil auf Systemcall-Ebene.
Danke fuer die Erklaerung!

Oh mann, worauf habe ich mich da eingelassen... ;-)
;-)
Ich versuche gerade mir das ganze aus den Manpages zu erschliessen. (Trotz mangelhaften Englischkenntnissen...)
Probier's mit dem Script und den anderen verlinkten Vorlesungsunterlagen, die sind Deutsch und fuehren dich sanfter ans Thema heran und erklaeren mehr als die Manpages.
Verstaendnissfrage zu fork und exec:
Mit dem Befehl >fork< erzeuge ich einen eigenstaendigen Kind-Prozess des Ursprungs-Progamms.
Das bedeutet, dass Programm wird komplett verdoppelt und beide befinden sich an der gleichen "Programmstelle".
Danach laufen beide Programm-Teile unabhaengig voneinander weiter.
Mit dem Befehl >execl< ersetze ich dann den Kind-Prozess oder das Ursprungs-Progamm durch z.B. bc.
Um den Kind-Prozess wieder zu beenden, lasse ich ihn einfach in ein exit laufen.
Ist das soweit korrekt?
Ja.
Mit den Pipes habe ich im Moment etwas groessere Verstaendnissprobleme...
Mit:
int pipes[2];
pipe(pipes);
erzeuge ich vor dem fork zwei Pipes (Lesen und Schreiben).
Nach dem fork besitzen beide Prozesse die gleichen pipes.
Das bedeutet, ich muss in einem der Prozesse die beiden pipes vertauschen. (Lesen wird zu Schreiben und umgekehrt.)
Ist das auch korrekt?
In dem Fall kann man das ``vertauchen'' nennen, allgemeiner gesagt, musst du jeweils das andere Ende schliessen. AFAIR hat's im verlinkten Script ein nettes Bild, wie aus der zweiendigen Pipe durch den Fork eine vierendige wird. Man kann aber nur zwei davon nutzen. Mit der zweiten Pipe genau das Gleiche, bloss halt anders rum.
Da beide Prozesse unabhaengig voneinander Laufen, woher wissen dann die Prozesse wer gerade "dran" ist?
Beide laufen gleichzeitig. Wenn du zwei Kerne hast, dann sogar wirklich gleichzeitig, sonst halt vom Scheduler des Betriebsstems quasi-parallel ausgefuehrt.
Wenn z.B. der Prozess, der die Berechnung durchfuehrt, etwas langsamer laeuft als der Prozess, der die Formeln versendet...
Die Pipe hat einen (Ring-)Puffer, der federt das ab. (Siehe Script, gleich auf der ersten Seite, glaube ich.)
Im Moment bin ich so weit, dass ich mittels >write< eine Formel an den Kind-Prozess senden kann und er mir dann das Ergebnis von bc in die Standardausgabe schreibt.
Das ist doch schon eine Menge.

Jetzt musst du bloss die zweite Pipe noch anlegen und richtig anschliessen, dann fliessen die Daten wieder von bc-(Kind-)Prozess wieder zum Haupt-(Parent-)Prozess zurueck, wo du sie dann lesen musst. Wenn du den Rest schon hast, ist das eigentlich das kleinste Problem. ;-)
Habe gerade etwas Probleme den Wald zu sehen, da noch lauter Baeume davor stehen. Aber ich bleibe dran...
Ja, weiter so! :THX:
Use ed(1) once in a while!

Antworten