[gelöst] Bash-Script: Befehle an eine Konsole übergeben

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
vitaminb
Beiträge: 57
Registriert: 22.02.2011 15:59:07

[gelöst] Bash-Script: Befehle an eine Konsole übergeben

Beitrag von vitaminb » 26.11.2012 08:46:21

Hallo,

ich habe hier ein kleines Tool (Remote-Konsole für einen Gameserver ... nein, kein Mindcraft ;) ) dessen Ausgabe ich über eine while-Schleife einlesen bzw. weiterverarbeiten möchte. Das Tool gibt in einer Dauerschleife Daten aus, kann aber auch Befehle annehmen die man direkt während der Laufzeit eintippt. Nun möchte ich bei bestimmten Vorkommnissen die das Tool meldet entsprechend reagieren und Befehle an das Tool übergeben.

Ich habe schon einiges versucht aber es mag nicht so recht gelingen. Es lässt sich bestimmt mit einer Umleitungen oder Pipe realisieren aber ich wüsste nicht wohin ich das umleiten soll ...

Hier mal ein gekürzter Auszug aus meinem Script:

Code: Alles auswählen

#!/bin/bash

INI="$1"
[ ! -f "$INI" ] && exit

ENTERSEQ=`echo -ne '\015'`
./yxz.run ini=$INI | while read -r OUTPUT; do 

	echo "["$(date +"%d-%m-%Y %T")"] $OUTPUT"
	[ "$OUTPUT" == "XYZ" ] && cat <<< "hello$ENTERSEQ"

done
Mit echo und cat komme ich hier anscheinend nicht weiter da die Ausgabe zwar auf dem Bildschirm erscheint, aber nicht als Befehl während der while-Schleife interpretiert wird.

Wenn das Script in einer screen-Session läuft kann ich mit folgendem Befehl einen weiteren Befehl an das Tool senden:

Code: Alles auswählen

ENTERSEQ=`echo -ne '\015'`
screen -S XYZ -p 0 -X stuff 'exit'$ENTERSEQ
Das soll aber auch ohne screen-Session funktionieren. Habt ihr eine Idee wie man das angehen könnte?

Gruß
Zuletzt geändert von vitaminb am 26.11.2012 20:48:29, insgesamt 1-mal geändert.

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von Cae » 26.11.2012 09:56:50

Du kannst mit zwei FIFOs arbeiten, die als dauerhafte Schnittstelle zu den FDs (hier namentlich stdin und stdout) wirken:

Code: Alles auswählen

#!/bin/sh

fifo0=stdin-fifo
fifo1=stdout-fifo

test -e "$fifo0" || mkfifo "$fifo0" # TODO: check for double instance
test -e "$fifo1" || mkfifo "$fifo1"

/foo/bar <"$fifo0" >"$fifo1" &

while read -r fnord <"$fifo1"; do
	echo "$fnord" | grep -q pattern && {
		echo -ne 'waaah!1!!\015' >"$fifo0"
		echo "$fnord" mail -s "waaah!" foo@example.org
	}
done
Du musst aufpassen, denn eine volle FIFO nimmt keine Daten mehr an. Es muss also staendig jemand ueber cat oder Eingabeumlenkung die FIFO leer nuckeln, insbesondere die fuer stdout. Und wenn aus irgendwelchen Gruenden zwei nuckeln, bekommt der zweite niemals Daten zu sehen, solange der erste nicht den Socket zu macht.
Ein weiterer Punkt ist der stderr-Kanal, fuer den es eine eigene FIFO braeuchte (/foo/bar 2>"$fifo2" >"$fifo1...) oder man mischt ihn in stdout mit hinein (/foo/bar >"$fifo1" 2>&1 <"...).

Uebrigens verwendest du keine expliziten Features der Bash, daher kannst du auch die schnellere und portablere Shell verwenden.

Gruss Cae

--Edit: oben das Kaufmannsund /foo/bar ... & ergaenzt.
Zuletzt geändert von Cae am 26.11.2012 14:22:06, insgesamt 1-mal geändert.
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

vitaminb
Beiträge: 57
Registriert: 22.02.2011 15:59:07

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von vitaminb » 26.11.2012 10:54:26

Hallo Cae,

danke für Deine Antwort. Ich versuche das genannte Beispiel anzuwenden aber komme leider nicht wirklich weiter.

Es geht konkret um die Punkbuster Client Konsole. Diese sendet mir Gameserver-Daten so lange wie es läuft in einer Dauerschleife weswegen der Programmaufruf sicher vor der while-Schleife genannt werden muss?

Code: Alles auswählen

#!/bin/sh

fifo0=stdin-fifo
fifo1=stdout-fifo

test -e "$fifo0" || mkfifo "$fifo0" # TODO: check for double instance
test -e "$fifo1" || mkfifo "$fifo1"

./yxz.run ini=$INI | while read -r OUTPUT <"$fifo1"; do
	echo "$OUTPUT" 
	echo "$OUTPUT" | grep -q pattern && {
		echo -ne 'waaah!1!!\015' >"$fifo0"
	}
done
Hierbei wird aber das Programm nicht mehr ausgeführt weil die while-Schleife sicherlich nur den Inhalt aus ... <"$fifo1" interpretieren möchte, richtig?
Zuletzt geändert von vitaminb am 26.11.2012 18:29:15, insgesamt 1-mal geändert.

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von Cae » 26.11.2012 14:21:39

vitaminb hat geschrieben:weil die while-Schleife sicherlich nur den Inhalt aus ... <"$fifo1" interpretieren möchte, richtig?
Gute Frage, ob das jetzt daran liegt, schliesslich ist da vorne eine Pipe dran. Keine Ahnung, wem die Shell dann Vorrang gibt, scheinbar ist es ja die Eingabeumleitung (oder wird das ineinander gemischt?). Da die FIFO nicht befuellt wird, passiert auch nix.

Jedenfalls musst du das mehr trennen. Das Tool laeuft *vor* der Schleife los (wichtige Ergaenzung, hinten in der Zeile muss ein & stehen, damit es tatsaechlich im Hintergrund rennt). Es kommuniziert ueber die FIFOs mit dem read, welches alleine in der Schleife haengt.

Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

vitaminb
Beiträge: 57
Registriert: 22.02.2011 15:59:07

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von vitaminb » 26.11.2012 15:31:06

Um das Beispiel noch einmal nachvollziehen zu können habe ich es im Großen und Ganzen übernommen und nur die Stelle /foo/bar ... mit tail -f /var/log/syslog .. ersetzt:

Code: Alles auswählen

#!/bin/bash

fifo0=stdin-fifo
fifo1=stdout-fifo

test -e "$fifo0" || mkfifo "$fifo0" # TODO: check for double instance
test -e "$fifo1" || mkfifo "$fifo1"

tail -f /var/log/syslog <"$fifo0" >"$fifo1" &

while read -r OUTPUT <"$fifo1"; do
	echo "$OUTPUT"
	echo "$OUTPUT" | grep -q pattern && {
		echo -ne 'waaah!1!!\015' >"$fifo0"
	}
done
Normal sollte hier ja jetzt aufgrund der Schleife die tail-Ausgabe erscheinen? Das passiert aber leider nicht - es wird gar nichts ausgegeben. Sehe aber auch keinen Fehler ... :?
Zuletzt geändert von vitaminb am 26.11.2012 18:30:13, insgesamt 1-mal geändert.

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von Cae » 26.11.2012 15:56:37

Das Problem ist das read, welches an dieser Stelle die Schleife beendet. An der Stelle braucht es das read aber gar nicht, weil ohnehin nur gegreppt werden soll. Vereinfachung:

Code: Alles auswählen

...
... mkfifo "$fifo1"

(while :; do cat <"$fifo0" >"$fifo1"; done) & # dummy

while :; do
	grep -q pattern "$fifo1" && {
		date >>log
		echo pattern matched >>log
		# mail, whatever , do something
	}
done
Anstatt der Dummy-Zeile (sie schreibt einfach aus der einen FIFO in die andere) kommt dein Programm von oben, genau so mit der Eingabeumleitung (und ohne die while-Schleife, aber mit &).

Das ist dann eine Endlosschleife, das sollte man gut debuggen, ehe es produktiv wird. Sonst hat man z.B. seeeehr schnell seeehr viele Mails. Evlt. : (true) durch sleep 1 oder so etwas ersetzen.

Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
r900
Beiträge: 1053
Registriert: 09.10.2011 20:06:11
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Stockholm

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von r900 » 26.11.2012 16:06:38

Cae hat geschrieben:Das Problem ist das read, welches an dieser Stelle die Schleife beendet
Die Umleitung muss hinter das "done", so sollte es gehen:

Code: Alles auswählen

while read -r OUTPUT ; do
   echo "$OUTPUT"
   echo "$OUTPUT" | grep -q "fileserver2" && {
      echo -ne 'waaah!1!!\015' > "$fifo0"
   }
done < "$fifo1"

vitaminb
Beiträge: 57
Registriert: 22.02.2011 15:59:07

Re: [Bash-Script] Befehle an eine Konsole übergeben

Beitrag von vitaminb » 26.11.2012 19:22:10

Ich habe jetzt nochmal mit dem o. g. Beispiel rumprobiert und es funktioniert nun genau wie ich es mir vorgestellt habe :THX:

Code: Alles auswählen

#!/bin/sh

fifo0=stdin-fifo
fifo1=stdout-fifo

test -e "$fifo0" || mkfifo "$fifo0" # TODO: check for double instance
test -e "$fifo1" || mkfifo "$fifo1"

/foo/bar <"$fifo0" >"$fifo1" &
echo -ne '\015' >"$fifo0"

while read -r OUTPUT; do
	echo "$OUTPUT"
	echo "$OUTPUT" | grep -q pattern && {
		echo "TRUE"
	}
done <"$fifo1"
Mit der while-Schleife kann ich Ereignisse abfragen und per echo "cmd" > stdin-fifo wie gewünscht reagieren und Befehle an den Server senden.

Ich danke euch beiden Cae und r900!

Gruß

Antworten