Como canalizar comandos para um processo em execução em segundo plano?

5

Este é o meu programa de loop, rodando em segundo plano e esperando por um comando.

#include <iostream>

using namespace std;

char buffer[256];

int main(int argc, char *argv[])
{
    while(true){
     fgets(buffer, 255, stdin);
     buffer[255] = 0;
     if(buffer[0] != '
myLoop &
'){ cout << buffer; buffer[0] = '
#include <iostream>

using namespace std;

char buffer[256];

int main(int argc, char *argv[])
{
    while(true){
     fgets(buffer, 255, stdin);
     buffer[255] = 0;
     if(buffer[0] != '
myLoop &
'){ cout << buffer; buffer[0] = '%pre%'; } } return 0; }
'; } } return 0; }

Eu corri com:

%pre%

Agora, como posso enviar um comando para esse processo?

    
por mamrezo 05.08.2017 / 18:24

3 respostas

13

Eu acho que isso é impossível com um pipeline "real".

Em vez disso, você pode usar um FIFO (pipe nomeado, veja man mkfifo ) ou (mais elegante, mas mais complicado) um socket Unix (AF_UNIX).

./background-proc </path/to/fifo &
cat >/path/to/fifo
# typing commands into cat

Eu não sou um desenvolvedor, então minha única relação com sockets é socat . Mas isso pode ajudar como um começo.

Você precisa de um "servidor" que se comunique com o seu programa. Tal pipeline seria iniciado em segundo plano:

socat UNIX-LISTEN:/tmp/sockettest,fork STDOUT | sed 's/./&_/g'

O sed é apenas para testes.

Então você começa um ou mais

socat STDIN UNIX-CONNECT:/tmp/sockettest

Se você tiver um programa que gere os comandos para seu programa em segundo plano, use um pipeline aqui também:

cmd_prog | socat STDIN UNIX-CONNECT:/tmp/sockettest

A vantagem em comparação com um FIFO é que (com a opção fork no lado do servidor) você pode desconectar e reconectar o cliente. Usando um FIFO, você precisaria de truques para manter o lado de recebimento em execução:

while true; do cat /path/to/fifo; done | background_prog
    
por 05.08.2017 / 18:37
4

Geralmente, você não pode alterar quais arquivos um processo abriu e para onde eles apontam de fora desse processo depois que o processo foi iniciado. Há exceções na forma de interfaces de depuração e ferramentas como repty que pode fazer isso de forma limitada.

Quando você iniciou seu programa com

myLoop &

sua entrada padrão foi conectada ao seu terminal (porque você não a redirecionou para outro local) e isso não mudará para um pipe.

Veja também Como anexar terminal a um processo separado?

    
por 05.08.2017 / 18:35
3

Se você quiser iniciar o comando em segundo plano e tiver um descritor de arquivo para enviar dados para ele por meio de um pipe.

Com zsh ou bash , você pode usar um redirecionamento para uma substituição de processo.

exec 3> >(cmd)

Em seguida, envie a saída com:

echo something >&3

E informe o final do arquivo com exec 3>&- .

Ainda com zsh e bash , você também pode fazer:

{ coproc cmd >&3 3>&-; } >&3

Isso é iniciar cmd como um co-processo, que inicia o processo com dois canais, um para entrada, um para saída, mas aqui, como queremos apenas aquele para entrada, restauramos o stdout de cmd ao do resto da concha.

Para enviar saída:

echo something >&p # with zsh
echo something >&"${COPROC[1]}" # with bash

Com yash , você pode usar redirecionamento de processo :

exec 3>(cmd)

Com qualquer shell parecido com o Bourne, você sempre pode fazer:

{ {
  echo something >&3
  echo whatever
  ...
} 3>&1 >&4 4>&- | cmd; } 4>&1

Isso não é exatamente o mesmo que iniciar cmd em segundo plano e executar comandos que enviam sua saída para cmd em que esses comandos são executados em um subshell e, para shells interativos, cmd também está em primeiro plano afetado por Ctrl + C, por exemplo), mas fora isso, é principalmente funcionalmente equivalente.

    
por 06.08.2017 / 17:17