2015-02-14 5 views
7

Ich versuche, eine dauerhafte Verbindung mit bash zu erstellen. Am Terminal 1, halte ich eine netcat als Server ausgeführt wird:Persistente Verbindung in Bash-Skript

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 

Am Terminal 2, I eine Fifo und halten eine Katze zu erstellen:

$ mkfifo fifo 
$ cat > fifo 

auf Terminal 3, ich mache das Fifo als Eingang zu einem Client netcat:

$ cat fifo | nc -v localhost 3000 
Connection to localhost 3000 port [tcp/*] succeeded! 

Am Terminal 4, sende ich, was ich will:

$ echo command1 > fifo 
$ echo command2 > fifo 
$ echo command3 > fifo 

zurück zum Terminal gehen 1, sehe ich die Befehle empfangen werden:

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 41722) 
command1 
command2 
command3 

Also, alles funktioniert. Aber wenn ich in einem Skript setzen, dass (I genannt, dass fifo.sh), bash nicht in der Lage ist, in Fifo zu schreiben:

Am Terminal 1, gleichen Zuhören Server:

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 

Am Terminal 2, I führen Sie das Skript:

#!/bin/bash 

rm -f fifo 
mkfifo fifo 
cat > fifo & 
pid1=$! 
cat fifo | nc -v localhost 3000 & 
pid2=$! 

echo sending... 
echo comando1 > fifo 
echo comando2 > fifo 
echo comando3 > fifo 

kill -9 $pid1 $pid2 

Der Ausgang im Terminal 2:

$ ./fifo.sh 
Connection to localhost 3000 port [tcp/*] succeeded! 
sending... 

Am Terminal 1 ich nur die connec sehen tion. Keine Befehle:

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 42191) 
Connection closed, listening again. 

Jede Idee, warum es nur interaktiv funktioniert? Oder gibt es eine andere Möglichkeit, eine persistente Verbindung nur mit Bash zu erstellen? Ich möchte nicht für Expect gehen, weil ich ein größeres Bash-Skript habe, das nach dem Senden des Befehls1 etwas Arbeit leistet, und command2 hängt vom Befehl1 ab usw.

Vielen Dank!

+1

Hallo und willkommen zu Stack Overflow! Das ist die beste Anfängerfrage, die ich je gesehen habe. – l0b0

Antwort

2

Wenn ein Prozess im Hintergrund in einem Skript gestartet wird, wird die Standardeingabe von /dev/null umgeleitet. Dies bedeutet, dass der erste cat Befehl EOF liest und ausgibt, sobald er ausgeführt wird, was bewirkt, dass netcat sofort nach dem Start beendet wird, so dass die Ausgabe später im Skript niemals zum FIFO gelangen wird, weil es keinen aktiven Listener gibt zu dieser Zeit.

In diesem Fall, wenn cat > fifo ausgewertet wird, gibt die Shell einen untergeordneten Prozess aus, leitet die Standardeingabe von /dev/null um und versucht, fifo zum Schreiben zu öffnen. Das Kind bleibt zu diesem Zeitpunkt in einem blockierenden open Anruf. Beachten Sie, dass cat erst ausgeführt wird, nachdem der Aufruf open abgeschlossen ist.

Als nächstes wird cat fifo | nc -v localhost 3000 erzeugt. cat öffnet fifo zum Lesen, wodurch die Blockierung open vom ersten Kind abgeschlossen und die erste cat ausgeführt werden kann.

Die erste cat erbt die Dateideskriptoren der Eltern, so dass ihre Standardeingabe an /dev/null angefügt ist, und sie liest und sendet sofort eine EOF.Die zweite cat liest die EOF und übergibt diese an den Standard-Eingang nc, die netcat zum Beenden führt. Wenn die echo-Anweisungen ausgewertet werden, sind die durch $pid1 und $pid2 identifizierten Prozesse abgeschlossen. Da es auf fifo keinen Listener mehr gibt, wird der erste echo für immer blockieren.


Ich habe keine reine Schale fix, aber Sie können ein externes Programm verwenden wie Perl den Platzhalter Schriftsteller fifo anstelle der Verwendung von Shell-Umleitung zu öffnen. Beachten Sie bitte, dass es ein Rennen mit nc gibt, das nach den echo Anweisungen beginnt (wo die kill passiert, bevor netcat eine Chance hat, Eingabe/sendende Ausgabe zu verarbeiten), also fügte ich hier eine Verzögerung nach dem Ausdruck cat | nc hinzu. Es ist fast sicher eine bessere Lösung gibt, aber hier ist, was ich kam mit:

#!/bin/bash 

rm -f fifo 
mkfifo fifo 
perl -e 'open(my $fh, ">", "fifo"); sleep 3600 while 1' & 
pid1=$! 
cat fifo | nc -v localhost 3000 & 
pid2=$! 

sleep 2 

echo sending... 
echo comando1 > fifo 
echo comando2 > fifo 
echo comando3 > fifo 

kill -9 $pid1 $pid2 

hoffte, das hilft, große Frage!