Verbindungseingang _and_output zwischen zwei Befehle in der Schale / bash
Frage
Ich habe zwei (UNIX) Programme A und B, die von stdin / stdout lesen und schreiben.
Mein erstes Problem ist, wie die Standardausgabe von A bis stdin von B verbinden und die stdout von B auf den stdin von A. D. h, so etwas wie A | B, sondern ein bidirektionaler Rohr. Ich vermute, ich könnte dieses Problem lösen, indem exec umleiten, aber ich konnte es nicht bekommen arbeiten. Die Programme sind interaktiv so eine temporäre Datei nicht funktionieren würde.
Das zweite Problem ist, dass ich mag jede Richtung und Rohr über ein Logging-Programm ein Duplikat duplizieren und stdout, dass ich die (Text-Linie basiert) Verkehr sehen, die zwischen den Programmen bestehen. Hier kann ich mit T-Stück weg> (...), wenn ich das erste Problem lösen kann.
Diese beiden Probleme scheinen, wie sollten sie auch Lösungen bekannt, aber ich habe nicht in der Lage sein, etwas zu finden.
Ich würde eine POSIX-Shell-Lösung bevorzugen, oder zumindest etwas, das in bash auf Cygwin funktioniert.
Dank Ihre Antworten kam ich mit der folgenden Lösung auf. Die A / B-Befehle verwendet nc zu zwei Ports zu hören. Das Logging-Programm verwendet sed (mit -u für ungepufferte Verarbeitung).
bash-3.2$ fifodir=$(mktemp -d)
bash-3.2$ mkfifo "$fifodir/echoAtoB"
bash-3.2$ mkfifo "$fifodir/echoBtoA"
bash-3.2$ sed -u 's/^/A->B: /' "$fifodir/echoAtoB" &
bash-3.2$ sed -u 's/^/B->A: /' "$fifodir/echoBtoA" &
bash-3.2$ mkfifo "$fifodir/loopback"
bash-3.2$ nc -l -p 47002 < "$fifodir/loopback" \
| tee "$fifodir/echoAtoB" \
| nc -l -p 47001 \
| tee "$fifodir/echoBtoA" > "$fifodir/loopback"
Das hört für den Anschluss an Port 47001 und 47002 und echos der gesamten Datenverkehrs auf der Standardausgabe.
In Schale 2 zu tun:
bash-3.2$ nc localhost 47001
In Schale 3 zu tun:
bash-3.2$ nc localhost 47002
Jetzt in der Schale eingegeben Linien 2 geschrieben werden 3 und umgekehrt, Shell und der Verkehr angemeldet 1, Shell, so etwas wie:
B->A: input to port 47001
A->B: input to port 47002
Das oben wurde auf Cygwin getestet
Update: Das Skript oben gestoppt, nachdem ein paar Tage arbeiten (!). Offenbar kann es Deadlock. Einige der Vorschläge in den Antworten können zuverlässiger sein.
Andere Tipps
Wie über eine Named Pipe?
# mkfifo foo
# A < foo | B > foo
# rm foo
Für Ihren zweiten Teil Ich glaube, T-Shirt ist die richtige Antwort. So wird es:
# A < foo | tee logfile | B > foo
Sie könnten wahrscheinlich mit Named Pipes weg:
mkfifo pipe
gawk '$1' < pipe | gawk '$1' > pipe
Sie können mit erwarten .
Erwarten Sie ist ein Werkzeug für die Automatisierung von interaktiven Anwendungen wie Telnet, FTP, passwd, fsck, rlogin, Spitze, etc.
Sie können den folgenden Code verwenden (aus dem Erwarten Explo Buch) als Ausgangspunkt - den Ausgang des proc1 an den Eingang des proc2 und umgekehrt verbindet, wie gewünscht:
#!/usr/bin/expect -f
spawn proc1
set proc1 $spawn_id
spawn proc2
interact -u $proc1
Ich habe auf diese viel Zeit, gab es auf, und zuletzt entschieden KSH (die Korn-Shell) zu verwenden, die dies ermöglicht.
cmd1 |& cmd2 >&p <&p
wobei |&
ist ein (Rohr) Bediener einen Coprozess und &p
ist Dateideskriptor dieses Co-Prozess zu starten.
Ich hatte dieses Problem an einem Punkt, und ich warf zusammen dieses einfache C-Programm.
#include <stdio.h>
#include <unistd.h>
#define PERROR_AND_DIE(_x_) {perror(_x_); _exit(1);}
int main(int argc, char **argv) {
int fd0[2];
int fd1[2];
if ( argc != 3 ) {
fprintf(stdout, "Usage %s: \"[command 1]\" \"[command 2]\"\n", argv[0]);
_exit(1);
}
if ( pipe(fd0) || pipe(fd1) ) PERROR_AND_DIE("pipe")
pid_t id = fork();
if ( id == -1 ) PERROR_AND_DIE("fork");
if ( id ) {
if ( -1 == close(0) ) PERROR_AND_DIE("P1: close 0");
if ( -1 == dup2(fd0[0], 0) ) PERROR_AND_DIE("P1: dup 0"); //Read my STDIN from this pipe
if ( -1 == close(1) ) PERROR_AND_DIE("P1: close 1");
if ( -1 == dup2(fd1[1], 1) ) PERROR_AND_DIE("P1: dup 1"); //Write my STDOUT here
execl("/bin/sh", "/bin/sh", "-c", argv[1], NULL);
PERROR_AND_DIE("P1: exec")
}
if ( -1 == close(0) ) PERROR_AND_DIE("P2: close 0");
if ( -1 == dup2(fd1[0], 0) ) PERROR_AND_DIE("P2: dup 0");
if ( -1 == close(1) ) PERROR_AND_DIE("P2: close 1");
if ( -1 == dup2(fd0[1], 1) ) PERROR_AND_DIE("P2: dup 1");
execl("/bin/sh", "/bin/sh", "-c", argv[2], NULL);
PERROR_AND_DIE("P2: exec")
}
Diese Frage ist ähnlich href="https://stackoverflow.com/questions/40244/how-to-make-a-pipe-loop-in-bash"> man Ich fragte vor . Die Lösungen von anderen vorgeschlagen wurden Named Pipes verwenden, aber ich vermute, Sie haben sie nicht in Cygwin. Zur Zeit bin ich klebe href="https://stackoverflow.com/questions/40244/how-to-make-a-pipe-loop-in-bash#43332"> meinen eigenen (Versuch a) Lösung , aber es erfordert /dev/fd/0
die Sie wahrscheinlich auch nicht haben.
Obwohl ich weiß nicht wirklich wie der Abwälzung Kommandozeilen-as-Strings Aspekt twinpipe
(erwähnt von JeeBee ( 139495 )), es könnte Ihre einzige Option in cygwin sein.
Ich würde vorschlagen, "coproc":
#! /bin/bash
# initiator needs argument
if [ $# -gt 0 ]; then
a=$1
echo "Question $a"
else
read a
fi
if [ $# -gt 0 ]; then
read a
echo "$a" >&2
else
echo "Answer to $a is ..."
fi
exit 0
Dann diese Sitzung finden Sie unter:
$ coproc ./dialog
$ ./dialog test < /dev/fd/${COPROC[0]} > /dev/fd/${COPROC[1]}
Answer to Question test is ...