Visualización de stdout de un proceso en segundo plano en una ubicación específica del terminal

8

Tengo un comando que ejecuto cada vez que se abre un nuevo terminal o se realiza un nuevo inicio de sesión.

Este programa produce una salida (coloreada) que debe colocarse antes del símbolo del sistema. Puede tardar unos segundos en ejecutarse, lo que me impedirá usar el terminal hasta entonces (a menos que se ejecute en segundo plano).

Dado que zsh tiene algunas formas avanzadas de volver a dibujar el terminal sin alterar el texto existente, me gustaría saber cómo puedo ejecutar este comando de una manera que no tenga que esperar a que termine antes de poder usar el terminal, pero eso una vez que termina, imprime la salida como si no estuviera en segundo plano en primer lugar.

En la práctica, me gustaría algo que pudiera hacer:

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

y una vez que termine el comando obtendría:

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

Intenté poner el proceso en segundo plano al inicio, pero luego no muestra la salida limpiamente. Me sale 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

Entonces, ¿es esto posible? Si no con zsh, ¿hay alguna solución que pueda hacerlo?

Cualquier sugerencia o información es bienvenida.

unode
fuente
No es posible si el programa se ejecuta directamente en el terminal, porque solo hay una posición del cursor y zsh y el programa competiría por él. Podría hacer algo con zpty: hacer que el comando se ejecute en un terminal creado por zsh, con su salida transmitida al terminal real bajo el control de zsh.
Gilles 'SO- deja de ser malvado'
@Gilles ¿Podría dar más detalles sobre el uso de zpty? Soy consciente de que no puedes tener dos programas escribiendo en el mismo terminal sin algún tipo de competencia sobre el cursor. Mi pregunta proviene del hecho de que zsh ya reescribe el indicador en algunas configuraciones. Obviamente, este programa tendría que escribir en algún búfer temporal en memoria que luego sería "impreso" en la ubicación específica una vez que finalice el comando. Todo esto último bajo control de zsh.
Unode
@Gilles: ¿tal vez esto valga una respuesta real?
Stéphane Gimenez
@ StéphaneGimenez Claro, lo es. No sé cómo hacerlo sin un poco de investigación, y no tengo tiempo para esta investigación en este momento.
Gilles 'SO- deja de ser malvado'
Una idea sería hacer esto con screenun script de inicio que divide la pantalla y ejecuta el corredor largo en la parte superior y la línea de comando normal en la parte inferior.
vasquez

Respuestas:

5

Esta es una solución simple si está dispuesto a aceptar resultados justo por encima de la línea de solicitud actual.

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

Cuando finalice el trabajo, se eliminarán la solicitud actual y el búfer de entrada stdouty stderrse imprimirán la totalidad de los comandos .

Usted puede conseguir mucho más elegante de lo que con el zsh/cursesmódulo, pero dudo que ofrecería una ventaja significativa suficiente para merecer el esfuerzo.

revs usuario112553
fuente
Esto funciona. Pero, ¿qué tan difícil sería evitar que el shell imprima el proceso pid cuando se envía a segundo plano y el mensaje "hecho" al finalizar? (Me refiero a desactivar temporalmente esa función). Además, antes de poner la salida en el terminal, ¿qué tan difícil sería borrar la línea o líneas de aviso existentes?
Unode
Creo que podría tener alguna otra configuración de reescritura del aviso que está colisionando con la eliminación del aviso inicial. El mío no desaparece una vez que finaliza el comando. También sigo recibiendo los PID de los procesos cuando se envían a segundo plano, pero la línea "hecho" se ha ido. En cualquier caso, estoy aceptando tu respuesta, ya que está bastante cerca de lo que tenía en mente. Gracias.
Unode
Estoy usando xterm y tengo el módulo VCS habilitado y algunas otras personalizaciones para el indicador. No lo he intentado, pero estoy bastante seguro de que está relacionado con eso. Hace algún tiempo intenté usar el notificador de modo vi similar a este ( stackoverflow.com/a/3791786/125801 ) y cuando estaba activo, perdí parte de mi comportamiento personalizado. No es gran cosa, por el momento estoy contento con la solución. Intentaré limpiar mi mensaje uno de estos días y verificar si los PID siguen apareciendo.
Unode
Zsh-4.3.10, después de deshabilitar casi todas las personalizaciones, ahora ya no recibo el mensaje (es decir, se eliminó correctamente), pero aún obtengo los PID de los procesos en segundo plano, como [1] 27911 27912en una sola línea y como la primera línea en el terminal.
Unode
¿Puedo votar de nuevo? :) ¡Es perfecto ahora! Gracias un montón.
Unode