Pelo que vejo, seus requisitos são:
- Execute várias instâncias do programa ao mesmo tempo.
- Obtenha o controle do terminal sobre qualquer uma das instâncias a qualquer momento.
- 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.