Jeder weiß , wie unidirektionale Leitung zwischen zwei Programmen zu machen (bind stdout
der ersten und stdin
der zweiten): first | second
.
Aber wie macht man bidirektionale Pipe, also Cross-Bind stdin
und stdout
von zwei Programmen? Gibt es eine einfache Möglichkeit, dies in einer Shell zu tun?
Nun, es ist ziemlich "einfach" mit Named Pipes (
mkfifo
). Ich habe es einfach in Anführungszeichen gesetzt, denn wenn die Programme nicht dafür ausgelegt sind, ist ein Deadlock wahrscheinlich.Normalerweise ist beim Schreiben von stdout eine Pufferung erforderlich. Wenn also zum Beispiel beide Programme:
Sie würden eine Endlosschleife erwarten. Aber stattdessen würden beide blockieren; Sie müssten hinzufügen
$| = 1
(oder eine Entsprechung), um die Ausgabepufferung zu deaktivieren. Der Deadlock wird verursacht, weil beide Programme auf etwas auf stdin warten, es aber nicht sehen, weil es sich im stdout-Puffer des anderen Programms befindet und noch nicht in die Pipe geschrieben wurde.Update : Vorschläge von Stéphane Charzelas und Joost einfließen lassen:
tut das gleiche, ist kürzer und portabler.
quelle
prog1 < fifo | prog2 > fifo
.prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.prog2 < fifo0 > fifo1
, können Sie Ihren kleinen Tanz vermeidenexec 30< ...
(was übrigens nur mitbash
oderyash
für FDS über 10 so funktioniert ).dash
scheint auch in Ordnung zu sein (verhält sich aber etwas anders)Ich bin mir nicht sicher, ob Sie dies versuchen:
Dies beginnt mit dem Öffnen eines Listening-Sockets an Port 8096, und sobald eine Verbindung hergestellt ist, wird ein Programm
second
mitstdin
dem Stream-Ausgang undstdout
dem Stream-Eingang erzeugt.Dann wird ein zweiter
nc
gestartet, der dem Listening - Port verbindet und laicht Programmfirst
mit seinenstdout
als Stromeingang und dessenstdin
als Strom ausgegeben.Dies geschieht nicht genau mit einer Pipe, aber es scheint zu tun, was Sie brauchen.
Da dies das Netzwerk verwendet, kann dies auf 2 Remotecomputern durchgeführt werden. Dies ist fast die Art
second
und Weise, wie ein Webserver ( ) und ein Webbrowser (first
) funktionieren.quelle
nc -U
für UNIX-Domain-Sockets, die nur den Adressraum des Dateisystems belegen.Sie können pipexec verwenden :
quelle
bash
Version 4 verfügt über einencoproc
Befehl, der dies in reinenbash
Pipes ohne Named Pipes ermöglicht:Einige andere Muscheln können das
coproc
auch.Nachfolgend finden Sie eine ausführlichere Antwort, die jedoch drei anstelle von zwei Befehlen verkettet, was ein wenig interessanter macht.
Wenn Sie auch gerne verwenden
cat
undstdbuf
dann konstruieren, kann das leichter verständlich gemacht werden.Version
bash
mitcat
undstdbuf
, leicht verständlich:Beachten Sie, dass Sie eval verwenden müssen, da die Variablenerweiterung in <& $ var in meiner Version von Bash 4.2.25 illegal ist.
Version using pure
bash
: In zwei Teile aufteilen, erste Pipeline unter Coproc starten, dann den zweiten Teil zu Mittag essen (entweder ein einzelner Befehl oder eine Pipeline) und wieder mit der ersten verbinden:Konzeptioneller Beweiß:
Datei
./prog
, nur ein Dummy-Programm zum Verzehren, Markieren und erneuten Drucken von Zeilen. Die Verwendung von Subshells, um Pufferprobleme zu vermeiden, kann zu einem Übermaß führen. Hier geht es nicht darum.Datei
./start_cat
Dies ist eine Version mitbash
,cat
undstdbuf
oder Datei
./start_part
. Dies ist eine Version, diebash
nur pure verwendet . Für Demozwecke verwende ich immer noch,stdbuf
weil Ihr echter Prog sich sowieso intern mit dem Puffern befassen müsste, um ein Blockieren aufgrund von Puffern zu vermeiden.Ausgabe:
Das tut es.
quelle
Ein praktischer Baustein zum Schreiben solcher bidirektionaler Pipes ist etwas, das die Standardausgabe und die Standardausgabe des aktuellen Prozesses miteinander verbindet. Nennen wir es Ioloop. Nach dem Aufruf dieser Funktion müssen Sie nur noch eine reguläre Pipe starten:
Wenn Sie die Deskriptoren der obersten Shell nicht ändern möchten, führen Sie diese in einer Subshell aus:
Hier ist eine portable Implementierung von ioloop mit einer Named Pipe:
Die Named Pipe ist im Dateisystem nur für kurze Zeit während des ioloop-Setups vorhanden. Diese Funktion ist nicht ganz POSIX, da mktemp veraltet ist (und möglicherweise für einen Rennangriff anfällig ist).
Eine linuxspezifische Implementierung mit / proc / ist möglich, für die keine Named Pipe erforderlich ist, aber ich denke, diese ist mehr als gut genug.
quelle
( : <$FIFO & )
um das genauer zu erklären . Vielen Dank für die Veröffentlichung.mktemp
? Ich benutze es ausgiebig, und wenn ein neueres Tool seinen Platz eingenommen hat, möchte ich damit beginnen.Es gibt auch
dpipe
, die "bidirektionale Pipe", die im vde2-Paket enthalten ist und in aktuellen Distributionspaket-Managementsystemen enthalten ist .dpipe processA = processB
socat , das Werkzeug , das alles mit allem verbindet.
socat EXEC:Program1 EXEC:Program2
Wie @ StéphaneChazelas in den Kommentaren richtig bemerkt, sind die obigen Beispiele die "Grundform", er hat schöne Beispiele mit Optionen für seine Antwort auf eine ähnliche Frage .
quelle
socat
Sockets anstelle von Pipes verwendet werden (Sie können dies mit änderncommtype=pipes
). Möglicherweise möchten Sie dienofork
Option hinzufügen , um zu vermeiden, dass ein zusätzlicher Socat-Prozess Daten zwischen den Pipes / Sockets verschiebt. (danke für die Bearbeitung meiner Antwort übrigens)Hier gibt es viele gute Antworten. Also möchte ich einfach etwas hinzufügen, um einfach mit ihnen herumzuspielen. Ich nehme an,
stderr
wird nirgendwo umgeleitet. Erstellen Sie zwei Skripte (sagen wir a.sh und b.sh):Dann, wenn Sie sie auf eine gute Weise verbinden, sollten Sie auf der Konsole sehen:
quelle