Каждый знает , как сделать однонаправленный трубу между двумя программами (связывают stdout
с первого и stdin
от второго): first | second
.
Но как сделать двунаправленную трубу, т.е. перекрестную привязку stdin
и stdout
две программы? Есть ли простой способ сделать это в оболочке?
Ну, это довольно просто с именованными каналами (
mkfifo
). Я легко пишу в кавычках, потому что если программы не предназначены для этого, скорее всего тупик.Теперь при написании stdout обычно используется буферизация. Так, например, если обе программы были:
вы ожидаете бесконечный цикл. Но вместо этого оба зашли бы в тупик; вам нужно будет добавить
$| = 1
(или эквивалент), чтобы отключить буферизацию вывода. Тупик вызван тем, что обе программы ожидают чего-то на stdin, но они этого не видят, потому что он находится в буфере stdout другой программы и еще не записан в канал.Обновление : включение предложений от Стефана Чарзела и Йоста:
делает то же самое, короче и более портативный.
источник
prog1 < fifo | prog2 > fifo
.prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.prog2 < fifo0 > fifo1
, вы можете избежать своего маленького танца сexec 30< ...
(который, кстати, работает только сbash
илиyash
для fds больше 10).dash
кажется, тоже хорошо (но ведет себя немного по-другому)Я не уверен, что это то, что вы пытаетесь сделать:
Это начинается с открытия прослушивающего сокета на порте 8096, и, как только соединение установлено, порождает программу
second
с егоstdin
выходнымstdout
потоком и входным потоком.Затем
nc
запускается секунда, которая соединяется с портом прослушивания и порождает программуfirst
с егоstdout
входнымstdin
потоком и выходным потоком.Это не совсем то, что делается с помощью канала, но, похоже, оно делает то, что вам нужно
Поскольку это использует сеть, это можно сделать на 2 удаленных компьютерах. Это почти то, как работают веб-сервер (
second
) и веб-браузер (first
).источник
nc -U
для доменных сокетов UNIX, которые занимают только адресное пространство файловой системы.Вы можете использовать pipexec :
источник
bash
В версии 4 естьcoproc
команда, которая позволяет делать это в чистом видеbash
без именованных каналов:Некоторые другие оболочки также могут делать то же самое
coproc
.Ниже приведен более подробный ответ, но он объединяет три команды, а не две, что делает лишь немного более интересным.
Если вы счастливы также использовать,
cat
аstdbuf
затем сделать конструкцию проще для понимания.Версия использования
bash
сcat
иstdbuf
, легко понять:Обратите внимание, нужно использовать eval, потому что расширение переменной в <& $ var недопустимо в моей версии bash 4.2.25.
Версия с использованием pure
bash
: разбить на две части, запустить первый конвейер в режиме coproc, а затем перекусить вторую часть (либо одну команду, либо конвейер), заново подключив его к первой:Подтверждение концепции:
файл
./prog
, просто фиктивная прога для потребления, пометки и повторной печати строк. Использование подоболочек, чтобы избежать проблем с буферизацией, может быть, излишним, но это не главноефайл
./start_cat
Это версия, использующаяbash
,cat
иstdbuf
или файл
./start_part
. Это версия, использующаяbash
только чистый . Для демонстрационных целей я все еще использую,stdbuf
потому что ваша настоящая прога должна была бы в любом случае иметь дело с внутренней буферизацией, чтобы избежать блокировки из-за буферизации.Выход:
Это делает это.
источник
Удобный строительный блок для написания таких двунаправленных каналов - это то, что соединяет stdout и stdin текущего процесса вместе. Давайте назовем это ioloop. После вызова этой функции вам нужно только запустить обычный канал:
Если вы не хотите изменять дескрипторы оболочки верхнего уровня, запустите это в подоболочке:
Вот переносимая реализация ioloop с использованием именованного канала:
Именованный канал существует в файловой системе ненадолго во время установки ioloop. Эта функция не совсем POSIX, потому что mktemp устарела (и потенциально уязвима для гонок).
Возможна специфичная для Linux реализация с использованием / proc /, для которой не требуется именованный канал, но я думаю, что этого более чем достаточно.
источник
( : <$FIFO & )
более подробно. Спасибо за публикацию.mktemp
? Я использую его широко, и если новый инструмент занял свое место, я хотел бы начать использовать его.Существует также
dpipe
«двунаправленная труба», включенная в пакет vde2 и включенная в существующие системы управления пакетами distro .dpipe processA = processB
Сокат , инструмент для соединения всего с чем-либо.
socat EXEC:Program1 EXEC:Program2
Как правильно замечает @ StéphaneChazelas в комментариях, приведенные выше примеры являются «базовой формой», у него есть хорошие примеры с вариантами ответа на аналогичный вопрос .
источник
socat
используются сокеты вместо каналов (вы можете изменить это с помощьюcommtype=pipes
). Возможно, вы захотите добавитьnofork
опцию, чтобы избежать дополнительного процесса socat, перемещающего данные между трубами / сокетами. (спасибо за редактирование моего ответа )Здесь много хороших ответов. Поэтому я просто хочу добавить что-нибудь, чтобы легко поиграть с ними. Я предполагаю,
stderr
что нигде не перенаправлен. Создайте два сценария (скажем, a.sh и b.sh):Затем, когда вы подключите их любым хорошим способом, вы должны увидеть на консоли:
источник