Múltipla instância do mesmo programa, obtendo saída

2

Eu tenho um programa shell no Ubuntu 16.04, chamado foo , que gera a atualização de status quando eu pressiono qualquer botão. Está localizado em /usr/local/bin/foo , então posso ligar para o programa em qualquer lugar. O programa funciona assim:

$ foo
Welcome

depois que eu pressionar uma tecla, será exibido:

Time now is 01:23:45

Se eu pressionar Ctrl-C , ele sairá como a maioria dos outros programas shell.

Eu gostaria que esse programa foo fosse executado em várias instâncias. Eu sei que o comando GNU Screen pode alternar entre tarefas, mas é a maneira correta de fazê-lo?

Como alternativa, sei que posso colocar o programa para ser executado em segundo plano assim:

$ foo &
[1]  123456

O ID do trabalho 1 é criado em segundo plano e eu posso chamá-lo por seu ID de trabalho:

$ fg %1

No entanto, eu preciso colocá-lo novamente em segundo plano depois de obter a última saída do programa (pressionando qualquer botão: existe algum método para fazer isso de forma programática?). Como posso conseguir isso?

    
por Raptor 13.07.2018 / 09:31

1 resposta

1

Pelo que vejo, seus requisitos são:

  1. Execute várias instâncias do programa ao mesmo tempo.
  2. Obtenha o controle do terminal sobre qualquer uma das instâncias a qualquer momento.
  3. Enviar as instâncias de volta ao segundo plano assim que elas saem.

Se nos mantivermos na abordagem & , então sim, existe um atalho para (3). Quando um programa tem controle sobre um terminal, ele pode ser enviado para o segundo plano usando um sinal SIGTSTP . Convenientemente, geralmente é o que Ctrl + Z faz.

Você poderia, portanto, ter algo assim:

$ foo &
Welcome
[1] 10

$ foo &
Welcome
[2] 11

$ fg %1
<ENTER>
Time now is 01:23:45
<Ctrl+Z>
[1]+ Stopped

No meu conhecimento, não existe esse atalho para fg (e como você indicaria qual instância recuperar de qualquer maneira?)

Observe que o sinal SIGTSTP não precisa realmente vir do shell que iniciou o processo. Se você kill -TSTP o processo por PID em um segundo shell, você também poderá recuperá-lo com fg no primeiro.

I need to put it back to background after obtaining the latest output of the program (by pressing any button: is there any method to do this programmatically?)

Se por programaticamente você indicar que tem acesso ao código-fonte de foo , poderá usar o que acabamos de ver. A chamada do sistema raise pode ser usada por um programa para enviar um sinal. Se tomarmos uma versão muito simplista de foo , podemos ter algo assim:

#include <stdio.h>
#include <signal.h>

int main(void)
{
    printf("Welcome");
    while(getchar()) { /* Use termios to switch to unbuffered mode */
        fprintf(stdout, "The time is... something");
        fflush(stdout);
        fflush(stdin);
        raise(SIGTSTP);
    }

    return 0;
}

Agora, apesar de tudo ser razoavelmente interessante, eu concordo que screen é provavelmente uma maneira mais agradável de fazer tudo isso, principalmente porque você pode nomear suas sessões de tela e, portanto, nunca precisa se lembrar de uma ID de trabalho ou processo. Assim como a abordagem & , ela também tem a vantagem de não exigir alterações no código-fonte.

$ screen -S foo1
$ ./foo
Welcome
<Ctrl-a d>
[detached from 10.foo1]

$ screen -s foo1
<ENTER>
Time now is 01:23:45
<Ctrl-a d>
[detached from 10.foo1]

Outra vantagem aqui é que você não precisa parar seu programa antes de desanexar. Isso é muito conveniente se você quiser fazer coisas em segundo plano enquanto não está procurando. Na abordagem anterior, você precisaria executar bg sempre que parar foo .

Você também pode obter uma lista de telas de execução com screen -ls . Na minha máquina, configurei alguns aliases em ~/.bashrc para explicar minha preguiça extra:

alias S='screen -S'
alias s='screen -r'
alias sls='screen -ls'

Desta forma, você poderia simplesmente fazer coisas como S foo1 , s foo1 , ... Alguns podem argumentar que aliases de um caractere podem ser um pouco irritantes quando você coloca um espaço ou algo em seus comandos, mas eu acho screen é um daqueles programas que são tão convenientes que você pode abrir uma exceção.

Agora, supondo que você esteja usando a abordagem screen , veja como você pode enviar uma chave para uma sessão e buscar sua última linha de saída de um shell. Existem maneiras de ajustar isso (e eu me permiti alguns atalhos), mas de qualquer maneira. Você pode definir a seguinte função em ~/.bashrc :

screen_key_tail() {
    screen -S $1 -X stuff "^M"
    tmp="$(mktemp)"
    screen -S $1 -X hardcopy "$tmp"
    grep -v ^$ "$tmp" | tail -n1
    rm "$tmp"
}

e ligue para:

$ screen_key_tail foo1

em que foo1 é o nome da sessão screen que você está segmentando.

    
por 13.07.2018 / 21:21