Każdy wie, jak sprawić, by rurę jednokierunkowy pomiędzy dwoma programami (wiążą się stdout
z pierwszego i stdin
drugiego jednego) first | second
.
Ale jak zrobić potok dwukierunkowy, tj. Wiązanie krzyżowe stdin
i stdout
dwóch programów? Czy istnieje prosty sposób, aby to zrobić w powłoce?
Cóż, jest dość „łatwy” z nazwanymi potokami (
mkfifo
). Wstawiam łatwe cytaty, ponieważ jeśli programy nie są zaprojektowane do tego, impas jest prawdopodobny.Teraz zwykle występuje buforowanie przy pisaniu standardowego wyjścia. Na przykład, jeśli oba programy były:
można oczekiwać nieskończonej pętli. Ale zamiast tego oba byłyby w impasie; musisz dodać
$| = 1
(lub równoważny), aby wyłączyć buforowanie danych wyjściowych. Zakleszczenie powstaje, ponieważ oba programy czekają na coś na standardowym wejściu, ale nie widzą tego, ponieważ znajduje się w buforze standardowego drugiego programu i nie zostało jeszcze zapisane w potoku.Aktualizacja : uwzględniająca sugestie Stéphane'a Charzelasa i Joosta:
robi to samo, jest krótszy i bardziej przenośny.
źródło
prog1 < fifo | prog2 > fifo
.prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.prog2 < fifo0 > fifo1
, można uniknąć swój mały taniec zexec 30< ...
(który nawiasem mówiąc działa tylko zbash
lubyash
do FDS ponad 10 tak).dash
wydaje się też OK (ale zachowuje się trochę inaczej)Nie jestem pewien, czy to właśnie próbujesz zrobić:
Zaczyna się to od otwarcia gniazda nasłuchującego na porcie 8096, a po ustanowieniu połączenia spawnuje program
second
zstdin
wyjściem strumienia istdout
wejściem strumienia.Następnie
nc
uruchamiany jest drugi, który łączy się z portem nasłuchującym i odradza programfirst
z jegostdout
wejściowym strumieniem istdin
wyjściowym strumieniem.Nie robi się tego dokładnie za pomocą potoku, ale wydaje się, że robi to, czego potrzebujesz.
Ponieważ korzysta to z sieci, można to zrobić na 2 komputerach zdalnych. W ten sposób działa prawie serwer WWW (
second
) i przeglądarka internetowa (first
).źródło
nc -U
dla gniazd domeny UNIX, które zajmują tylko przestrzeń adresową systemu plików.Możesz użyć pipexec :
źródło
bash
wersja 4 macoproc
polecenie, które pozwala to zrobić w czystej postacibash
bez nazwanych potoków:Niektóre inne powłoki również mogą to zrobić
coproc
.Poniżej znajduje się bardziej szczegółowa odpowiedź, ale łączy trzy polecenia zamiast dwóch, co czyni tylko trochę bardziej interesującym.
Jeśli jesteś szczęśliwy w użyciu,
cat
astdbuf
następnie skonstruowanie może być łatwiejsze do zrozumienia.Wersja korzystająca
bash
zcat
istdbuf
łatwa do zrozumienia:Zauważ, że muszę użyć eval, ponieważ rozszerzenie zmiennych w <& $ var jest nielegalne w mojej wersji bash 4.2.25.
Wersja z użyciem pure
bash
: Podziel na dwie części, uruchom pierwszy potok w ramach coproc, a następnie uruchom drugą część (jedno polecenie lub potok) ponownie łącząc go z pierwszą:Dowód koncepcji:
plik
./prog
, tylko sztuczny program do konsumpcji, oznaczania i ponownego drukowania linii. Używanie podpowłoki w celu uniknięcia problemów z buforowaniem może być nadmierne, nie o to tutaj chodzi.file
./start_cat
To jest wersja użyciubash
,cat
astdbuf
lub plik
./start_part
. To jest wersja wykorzystującabash
wyłącznie czysty . Do celów demonstracyjnych wciąż używam,stdbuf
ponieważ twój prawdziwy program musiałby i tak zająć się buforowaniem wewnętrznym, aby uniknąć blokowania z powodu buforowania.Wynik:
To wystarczy
źródło
Wygodnym elementem składowym do pisania takich dwukierunkowych potoków jest coś, co łączy stdout i stdin bieżącego procesu razem. Nazwijmy to Ioloop. Po wywołaniu tej funkcji wystarczy uruchomić zwykły potok:
Jeśli nie chcesz modyfikować deskryptorów powłoki najwyższego poziomu, uruchom to w podpowłoce:
Oto przenośna implementacja ioloop za pomocą nazwanego potoku:
Nazwany potok istnieje w systemie plików tylko na krótko podczas instalacji ioloop. Ta funkcja nie jest całkiem POSIX, ponieważ mktemp jest przestarzały (i potencjalnie podatny na atak rasowy).
Możliwe jest wdrożenie specyficzne dla systemu Linux przy użyciu / proc /, które nie wymaga nazwanego potoku, ale myślę, że ten jest wystarczająco dobry.
źródło
( : <$FIFO & )
bardziej szczegółowo. Dziękujemy za wysłanie.mktemp
? Używam go intensywnie, a jeśli zastąpi go nowsze narzędzie, chciałbym zacząć z niego korzystać.Jest również
dpipe
, „rura dwukierunkowa”, zawarta w pakiecie vde2 i zawarta w obecnych systemach zarządzania pakietami dystrybucyjnymi .dpipe processA = processB
socat , narzędzie do łączenia wszystkiego z wszystkim.
socat EXEC:Program1 EXEC:Program2
Jak @ StéphaneChazelas poprawnie zauważa w komentarzach, powyższe przykłady są „formą podstawową”, ma ładne przykłady z opcjami odpowiedzi na podobne pytanie .
źródło
socat
używa gniazd zamiast rur (możesz to zmienić za pomocącommtype=pipes
). Możesz dodaćnofork
opcję, aby uniknąć dodatkowego procesu spychania danych między rurami / gniazdami. (dzięki za edycję mojej odpowiedzi btw)Jest tu wiele świetnych odpowiedzi. Chcę tylko dodać coś, co pozwoli im się z nimi dobrze bawić. Zakładam, że
stderr
nie jest nigdzie przekierowywany. Utwórz dwa skrypty (powiedzmy a.sh i b.sh):Następnie, gdy podłączysz je w jakikolwiek dobry sposób, powinieneś zobaczyć na konsoli:
źródło