Exibindo stdout de um processo em segundo plano em local específico do terminal

8

Eu tenho um comando que eu executo sempre que um novo terminal é aberto ou um novo login é feito.

Este programa produz saída (colorida) que deve ser posicionada antes do prompt de comando. Pode demorar alguns segundos para executar, o que me impedirá de usar o terminal até então (a menos que seja executado em segundo plano).

Dado que o zsh possui algumas maneiras avançadas de redesenhar o terminal sem prejudicar o texto existente, eu gostaria de saber como executar este comando de uma maneira que não precise esperar que ele termine antes de poder usar o terminal, mas que uma vez finalizado, imprime a saída como se não estivesse em segundo plano em primeiro lugar.

Na prática, eu gostaria de algo que pudesse fazer:

Command output:
... (running on background)
me@computer: somecommand
me@computer: someothercommand

e quando o comando termina, eu recebo:

Command output:
 * Output foo
 * Multiple lines bar
 * and some yada
me@computer: somecommand
me@computer: someothercommand

Tentei colocar o processo em segundo plano no início, mas ele não exibe a saída corretamente. Eu recebo algo como:

Command output:
[2] 32207
me@computer: somecommand
me@computer: someother * Output foo
 * Multiple lines bar
 * and some yada
[2]  + done       command
me@computer: someothercommand

Então, isso é possível? Se não estiver com o zsh, existe alguma solução por aí que possa fazê-lo?

Quaisquer sugestões ou informações são bem-vindas.

unode
fonte
Não é possível se o programa estiver sendo executado diretamente no terminal, porque há apenas uma posição do cursor e zsh e o programa estaria competindo por ele. Você pode fazer algo com zpty: executar o comando em um terminal criado pelo zsh, com sua saída retransmitida para o terminal real sob o controle do zsh.
Gilles 'SO- stop be evil'
@Gilles Você poderia elaborar sobre o uso de zpty? Estou ciente de que você não pode ter dois programas gravando no mesmo terminal sem algum tipo de competição pelo cursor. Minha pergunta vem do fato de que o zsh já reescreve o prompt em algumas configurações. Obviamente, esse programa precisaria gravar em algum buffer temporário da memória que seria "impresso" no local específico assim que o comando fosse concluído. Todos estes últimos sob controle do zsh.
unode
@ Gilles: talvez isso valha a pena uma resposta real?
Stéphane Gimenez
@ StéphaneGimenez Claro que sim. Não sei como fazer isso sem alguma pesquisa e não tenho tempo para essa pesquisa no momento.
Gilles 'SO- stop be evil'
Uma idéia seria fazer isso com screenum script de inicialização que divide a tela e executa o corredor longo na parte superior e a linha de comando normal na parte inferior.
22412 vasquez

Respostas:

5

Esta é uma solução simples se você estiver disposto a aceitar a saída logo acima da linha de prompt atual.

TRAPUSR1 () { zle -I; unfunction TRAPUSR1 }  # invalidate prompt on signal USR1

bufferout () {
    local buffer
    while read -r line; do                   # buffer lines from stdin
        buffer="$buffer$line\n"
    done
    print -rn -- $terminfo[dl1]              # delete current line
    print -rn -- $terminfo[cr]               # move cursor to BOL
    printf "$buffer"                         # print buffer
    kill -USR1 $$                            # send USR1 when we're done
}

unsetopt monitor                             # don't monitor this job
./testout |& bufferout & disown              # bg and disown to suppress notification
setopt monitor                               # restore job monitoring

Quando o trabalho estiver concluído, o prompt atual e o buffer de entrada serão removidos e a totalidade dos comandos stdoute stderrserá impressa.

Você pode ficar muito mais sofisticado do que isso com o zsh/cursesmódulo, mas duvido que ofereceria uma vantagem significativa o suficiente para merecer o esforço.

user112553
fonte
Isso funciona. Mas quão difícil seria impedir o shell de imprimir o processo quando enviado para segundo plano e a mensagem "concluído" após a conclusão? (Quero dizer, desativar temporariamente esse recurso). Além disso, antes de colocar a saída no terminal, quão difícil seria limpar a linha ou linhas de prompt existentes?
unode 16/02/2012
Eu acho que posso ter alguma outra configuração de reescrita de prompt que está colidindo com a exclusão do prompt inicial. O meu não desaparece quando o comando termina. Também recebo os PIDs dos processos quando enviados para segundo plano, mas a linha "concluído" se foi. De qualquer forma, estou aceitando sua resposta, pois ela está bem próxima do que eu tinha em mente. Obrigado.
unode
Estou usando o xterm e tenho o módulo VCS ativado e algumas outras personalizações no prompt. Eu não tentei, mas tenho certeza que está relacionado com isso. Algum tempo atrás, tentei usar o notificador do modo vi semelhante a este ( stackoverflow.com/a/3791786/125801 ) e, quando ativo, perdi parte do meu comportamento de prompt personalizado. Não é grande coisa, no momento estou feliz com a solução. Vou tentar limpar meu prompt um dia desses e verificar se os PIDs ainda aparecem.
unode
Zsh-4.3.10, depois de desativar praticamente todas as personalizações, agora não recebo mais o prompt (ou seja, ele é removido corretamente), mas ainda recebo os PIDs dos processos em segundo plano, como [1] 27911 27912em uma única linha e como a primeira linha no terminal.
unode
Posso votar novamente? :) Está perfeito agora! Muito obrigado.
unode