Todo mundo sabe como fazer tubo unidirecional entre dois programas (ligamento stdout
de primeiro e stdin
de segundo): first | second
.
Mas como fazer tubo bidirecional, ou seja, ligação cruzada stdin
e stdout
de dois programas? Existe uma maneira fácil de fazer isso em uma concha?
Bem, é bastante "fácil" com pipes nomeados (
mkfifo
). Coloquei aspas fáceis porque, a menos que os programas sejam projetados para isso, é provável que haja um impasse.Agora, normalmente há buffer envolvido na gravação de stdout. Então, por exemplo, se os dois programas fossem:
você esperaria um loop infinito. Mas, em vez disso, ambos entrariam em impasse; você precisaria adicionar
$| = 1
(ou equivalente) para desativar o buffer de saída. O impasse é causado porque os dois programas estão aguardando algo no stdin, mas não o estão vendo porque está no buffer stdout do outro programa e ainda não foi gravado no canal.Atualização : incorporando sugestões de Stéphane Charzelas e Joost:
faz o mesmo, é mais curto e mais portátil.
fonte
prog1 < fifo | prog2 > fifo
.prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.prog2 < fifo0 > fifo1
, você pode evitar a sua pequena dança comexec 30< ...
(que por sinal só funciona combash
ouyash
para fds acima de 10 assim).dash
parece OK também (mas comporta-se um pouco diferente)Não tenho certeza se é isso que você está tentando fazer:
Isso começa abrindo um soquete de escuta na porta 8096 e, uma vez que uma conexão é estabelecida, gera um programa
second
comstdin
a saída de fluxo estdout
a entrada de fluxo.Em seguida, uma segunda
nc
é lançado, que conecta-se à porta de escuta e gera programafirst
com ostdout
que a entrada corrente e a suastdin
como o fluxo de saída.Isso não é exatamente feito usando um pipe, mas parece fazer o que você precisa.
Como isso usa a rede, isso pode ser feito em 2 computadores remotos. É quase assim que um servidor web (
second
) e um navegador web (first
) funcionam.fonte
nc -U
para soquetes de domínio UNIX que ocupam apenas espaço de endereço do sistema de arquivos.Você pode usar o pipexec :
fonte
bash
a versão 4 possui umcoproc
comando que permite que isso seja feito de forma pura,bash
sem pipes nomeados:Algumas outras conchas também podem funcionar
coproc
.Abaixo está uma resposta mais detalhada, mas encadeia três comandos, em vez de dois, o que torna um pouco mais interessante.
Se você estiver feliz em usar
cat
estdbuf
construir, pode ser mais fácil de entender.Versão usando
bash
comcat
estdbuf
fácil de entender:Observe que é necessário usar eval porque a expansão variável em <& $ var é ilegal no meu versio do bash 4.2.25.
Versão usando pure
bash
: Divida em duas partes, inicie o primeiro pipeline sob coproc e depois alimente a segunda parte ((um único comando ou um pipeline) reconectando-o à primeira:Prova de conceito:
arquivo
./prog
, apenas um programa fictício para consumir, marcar e reimprimir linhas. Usar sub-conchas para evitar problemas de buffer talvez exagere, não é o ponto aqui.file
./start_cat
Esta é uma versão usandobash
,cat
estdbuf
ou arquivo
./start_part
. Esta é uma versão usandobash
apenas puro . Para fins de demonstração, ainda estou usando,stdbuf
porque seu programa real precisaria lidar com o buffer internamente de qualquer maneira, para evitar o bloqueio devido ao buffer.Resultado:
Isso faz.
fonte
Um bloco de construção conveniente para escrever esses tubos bidirecionais é algo que conecta o stdout e o stdin do processo atual. Vamos chamá-lo de ioloop. Depois de chamar esta função, você só precisa iniciar um canal normal:
Se você não deseja modificar os descritores do shell de nível superior, execute isso em um subshell:
Aqui está uma implementação portátil do ioloop usando um pipe nomeado:
O pipe nomeado existe no sistema de arquivos apenas brevemente durante a configuração do ioloop. Esta função não é bem POSIX porque o mktemp está obsoleto (e potencialmente vulnerável a um ataque de corrida).
É possível uma implementação específica do linux usando / proc / que não exija um pipe nomeado, mas acho que este é mais que suficiente.
fonte
( : <$FIFO & )
com mais detalhes. Obrigado por postar.mktemp
? Eu o uso extensivamente e, se uma ferramenta mais recente tiver sido substituída, gostaria de começar a usá-la.Há também
dpipe
, o "tubo bidirecional", incluído no pacote vde2 e nos sistemas atuais de gerenciamento de pacotes de distribuição .dpipe processA = processB
socat , a ferramenta conectar tudo a tudo.
socat EXEC:Program1 EXEC:Program2
Como @ StéphaneChazelas observa corretamente nos comentários, os exemplos acima são o "formulário base", ele tem bons exemplos com opções em sua resposta para uma pergunta semelhante .
fonte
socat
usa soquetes em vez de tubos (você pode alterar isso comcommtype=pipes
). Você pode adicionar anofork
opção para evitar um processo socat extra que empurra dados entre os tubos / soquetes. (obrigado pela edição na minha resposta )Há muitas ótimas respostas aqui. Então, eu só quero adicionar algo para facilitar a brincadeira com eles. Presumo que
stderr
não seja redirecionado para lugar nenhum. Crie dois scripts (digamos a.sh e b.sh):Então, quando você os conectar da melhor maneira possível, você verá no console:
fonte