Wie erstelle ich ein Shell-Skript, das die Ausgabe an einen Prozess sendet?

11

Ich führe derzeit ein Serverkonsolenprogramm auf einem Bildschirm aus, da ich es sowohl lesen als auch gelegentlich Befehle senden muss.

Ich möchte die App als Daemon im Hintergrund ausführen (mit init starten / stoppen).

Ich könnte tail -fdas Protokoll erstellen, aber dadurch kann ich keine Eingaben an den Prozess senden.

Gibt es eine Möglichkeit, dies so einzurichten, dass ich Eingaben lesen und senden kann, sie aber immer noch im Hintergrund laufen lassen?

Ich möchte auch in der Lage sein, Eingaben von verschiedenen Prozessen an den Dämon zu senden (ein Shell-Skript, das beispielsweise einen "Stop \ n" -Befehl senden könnte).

Bill K.
quelle
Nur ein Kommentar an alle, die kommen, um dies zu lesen - die Antwort hier ist fantastisch. Wenn Sie sich mit Named Pipes nicht auskennen, empfehle ich Ihnen dringend, sie zumindest einmal auszuprobieren. Auf diese Weise könnte ich Minecraft als Dienst ausführen und über andere Skripte mit der Konsole interagieren, indem ich in die Named Pipe schreibe. So wird es möglich, Skripte zu schreiben, um den Server zu stoppen, Nachrichten an die Benutzer zu senden usw., während das Ausgabeprotokoll noch analysiert wird nach Schlüsselzeilen suchen (z. B. Chat-Nachrichten an einen Benutzer als Text senden)
Bill K

Antworten:

9

Aus einer Pipe lesen, in eine Datei schreiben

Wenn der Dämon Eingaben lesen soll, die von einem beliebigen Prozess erzeugt wurden, müssen Sie diesen Prozess mit einer Pipe verbinden. Hier gibt der beliebige Prozess das Echo von Befehlen wieder und wird in einem anderen Kontext ausgeführt. Erstellen Sie also eine Named Pipe (in Unix-Kontexten oft als Fifo bezeichnet).

mkfifo /var/run/daemon.fifo
</var/run/daemon.fifo /path/to/daemond --option >daemon.log

Und schreiben Sie einfach Befehle in die Pipe:

echo 'FORWARD 10' >/var/run/daemon.fifo
echo 'LEFT 72' >/var/run/daemon.fifo

Es ist jedoch unwahrscheinlich, dass dies so funktioniert: Es besteht eine gute Chance, dass der Dämon beendet wird, wenn er ein Dateiende an seiner Standardeingabe sieht. Dies geschieht, sobald der erste Prozess, der in die Pipe schreibt, beendet wird. Sie können tail -fdieses Problem vermeiden.

</var/run/daemon.fifo tail -c +1 -f | {
  echo $$ >/var/run/daemon.pid
  exec /path/to/daemond --option >daemon.log
}

Bei einigen tailImplementierungen kann es sein, dass Sie durch Pufferung gebissen werden: Der tailProzess wartet, bis er genügend Bytes angehäuft hat, um eine Ausgabe auszugeben. Ich denke nicht, dass dies in der POSIX-Toolbox lösbar ist. Wenn dies ein Problem ist, verwenden Sie ein einfaches C-, Perl- oder Python-Programm. Soweit ich das tailbeurteilen kann, sind die von GNU Coreutils (wie sie unter Linux und anderswo zu finden sind) in dieser Hinsicht sicher.

Wenn Sie den Dämon stoppen, echo >/var/run/daemon.fifowird der tailProzess abgebrochen.


Programm im Bildschirm starten

Anstatt den Daemon direkt von Ihrem Service Manager aus aufzurufen (verwenden Sie wirklich nur SysV init oder etwas Zusätzliches wie Wrapper-Skripte oder Upstart?), Rufen Sie auf

screen -c daemon.screenrc -L -d -m -S daemon_name /path/to/daemond --option

Da der Daemon kein untergeordneter Prozess des Service Managers ist, müssen Sie sicherstellen, dass ein Signal an den richtigen Prozess gesendet wird. Wie das geht, hängt davon ab, wie und von was der Daemon gestartet wird.

Es ist technisch möglich , einen laufenden Prozess an ein Terminal anzuschließen, aber es besteht die Gefahr, dass Sie das Programm zum Absturz bringen. Dies ist also definitiv für ein Produktionssystem nicht der Fall.

Mit dieser -LOption schreibt der Bildschirm alles, was in seinem Fenster angezeigt wird, in eine Datei. Der Dateiname wird daemon.screenrcmit der logfileDirektive angegeben.

Gilles 'SO - hör auf böse zu sein'
quelle
Eigentlich möchte ich wirklich in der Lage sein, Nachrichten aus einem Skript an den Standard zu senden - vielleicht ist das die Frage, die ich hätte stellen sollen. Momentan starte ich den Server nur über ein Skript und kann ihn in ein Terminal
Bill K
@ Bill: Ok, ich verstehe. Dann fällt mir als erstes eine Named Pipe ein.
Gilles 'SO - hör auf böse zu sein'
Ich denke das ist genau das was ich will @Gilles! Ich muss es aber besser verstehen. Ich werde einige Zeit damit verbringen, Manpages zu durchsuchen, um es herauszufinden - ich bekomme ehrlich gesagt sehr wenig davon (ich bekomme das meiste von dem, was du tust und fast nichts davon, wie du es getan hast - und ich dachte, ich hätte irgendwie eine Hinweis auf dieses Zeug.) Meine Theorie war nicht, sich direkt mit dem Prozess zu verbinden, sondern ein weiteres Skript zu erstellen, das I / O mit den Deamons O / I verbindet, damit es so aussieht, als würde die ursprüngliche Konsole ausgeführt, aber mit der Fähigkeit um gleichzeitig das Echo 'FORWARD 10' von einem anderen Skript zu machen.
Bill K
Ich glaube, ich bekomme viel davon. Wenn ich es kaputt mache, verstehe ich jetzt "mkfifo pipe" und "tail -f pipe | command> output", habe diese getestet und sie funktionieren. Ich denke, die meisten anderen Dinge, die Sie hatten, waren Tricks, um es in einer Zeile zum Laufen zu bringen - vermisse ich etwas Kritisches?
Bill K
@Bill: Sie können von außen (mit dem stuffBefehl des Bildschirms ) auf das Terminal innerhalb des Bildschirms schreiben . Aber Sie brauchen hier nicht den Overhead (Verarbeitung, aber vor allem kognitiv) eines Terminals, eine Pipe ist fast genug (es reicht mit einem kleinen Relay-Prozess, bei dem das Ende der Datei ignoriert wird). Vielleicht möchten Sie ein wenig mit <fifo catoder <fifo tail -f | catin einem Terminal und echo >fifo; echo >fifoin einem anderen Terminal experimentieren . Ich denke, es wird dir gut gehen.
Gilles 'SO - hör auf böse zu sein'