Anzeigen der Standardausgabe eines Hintergrundprozesses an einer bestimmten Position des Terminals

8

Ich habe einen Befehl, den ich jedes Mal ausführe, wenn ein neues Terminal geöffnet oder eine neue Anmeldung vorgenommen wird.

Dieses Programm erzeugt eine Ausgabe (farbig), die vor der Eingabeaufforderung positioniert werden sollte. Die Ausführung kann einige Sekunden dauern, sodass ich das Terminal bis dahin nicht verwenden kann (sofern es nicht im Hintergrund ausgeführt wird).

Angesichts der Tatsache, dass zsh einige erweiterte Möglichkeiten zum Neuzeichnen des Terminals bietet, ohne vorhandenen Text zu überfrachten, möchte ich wissen, wie ich diesen Befehl so ausführen kann, dass ich nicht warten muss, bis er abgeschlossen ist, bevor ich das Terminal verwenden kann Sobald es fertig ist, wird die Ausgabe so gedruckt, als ob sie überhaupt nicht im Hintergrund wäre.

In der Praxis möchte ich etwas, das tun könnte:

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

und sobald der Befehl beendet ist, würde ich bekommen:

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

Ich habe versucht, den Prozess beim Start in den Hintergrund zu stellen, aber dann wird die Ausgabe nicht sauber angezeigt. Ich bekomme so etwas wie:

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

Ist das also möglich? Wenn nicht mit zsh, gibt es da draußen eine Lösung, die das könnte?

Hinweise oder Informationen sind willkommen.

unode
quelle
Es ist nicht möglich, wenn das Programm direkt im Terminal ausgeführt wird, da es nur eine Cursorposition und zsh gibt und das Programm darum konkurrieren würde. Sie könnten Folgendes tun zpty: Lassen Sie den Befehl in einem von zsh erstellten Terminal ausführen, dessen Ausgabe unter der Kontrolle von zsh an das reale Terminal weitergeleitet wird.
Gilles 'SO - hör auf böse zu sein'
@ Gilles Könnten Sie die Verwendung von näher erläutern zpty? Mir ist bewusst, dass Sie nicht zwei Programme haben können, die auf dasselbe Terminal schreiben, ohne dass eine Konkurrenz um den Cursor besteht. Meine Frage kommt von der Tatsache, dass zsh die Eingabeaufforderung in einigen Konfigurationen bereits neu schreibt. Offensichtlich müsste dieses Programm in einen temporären In-Memory-Puffer schreiben, der dann nach Beendigung des Befehls an die bestimmte Stelle "gedruckt" wird. Alle letzteren unter der Kontrolle von zsh.
Unode
@ Gilles: Vielleicht ist das eine echte Antwort wert?
Stéphane Gimenez
@ StéphaneGimenez Sicher ist es. Ich weiß nicht, wie ich es ohne Forschung machen soll, und ich habe momentan keine Zeit für diese Forschung.
Gilles 'SO - hör auf böse zu sein'
Eine Idee wäre, dies mit screeneinem Startskript zu tun , das den Bildschirm aufteilt und den langen Läufer im oberen Teil und die normale Befehlszeile im unteren Teil ausführt.
Vasquez

Antworten:

5

Dies ist eine einfache Lösung, wenn Sie bereit sind, Ausgaben direkt über der aktuellen Eingabeaufforderungszeile zu akzeptieren.

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

Wenn die Arbeit erledigt ist, werden die aktuelle Eingabeaufforderung und Eingangspuffer des Befehls der entfernt und das Teilen stdoutund stderrgedruckt werden.

Sie können mit dem zsh/cursesModul viel ausgefallener werden, aber ich bezweifle, dass es einen Vorteil bietet, der bedeutend genug ist, um die Mühe zu verdienen.

user112553
quelle
Das funktioniert. Aber wie schwer wäre es zu verhindern, dass die Shell die Prozess-PID druckt, wenn sie in den Hintergrund gesendet wird und die Meldung "Fertig" nach Abschluss? (Ich meine, diese Funktion vorübergehend deaktivieren). Wie schwierig wäre es, die vorhandene Eingabeaufforderungszeile oder -zeilen zu löschen, bevor die Ausgabe auf das Terminal gestellt wird?
Unode
Ich glaube, ich habe möglicherweise eine andere Konfiguration zum Umschreiben der Eingabeaufforderung, die mit dem Löschen der ersten Eingabeaufforderung kollidiert. Meins verschwindet nicht, sobald der Befehl beendet ist. Ich erhalte auch immer noch die PIDs der Prozesse, wenn sie in den Hintergrund gesendet werden, aber die Zeile "Fertig" ist weg. Auf jeden Fall akzeptiere ich Ihre Antwort, da sie ziemlich nahe an dem liegt, was ich mir vorgestellt habe. Vielen Dank.
Unode
Ich verwende xterm und habe das VCS-Modul aktiviert und einige andere Anpassungen an der Eingabeaufforderung vorgenommen. Ich habe es nicht versucht, aber ich bin mir ziemlich sicher, dass es damit zusammenhängt. Vor einiger Zeit habe ich versucht, den ähnlichen vi-Modus- Notifier ( stackoverflow.com/a/3791786/125801 ) zu verwenden, und als ich aktiv war, habe ich einige meiner benutzerdefinierten Eingabeaufforderungsverhalten verloren. Es ist keine große Sache, im Moment bin ich mit der Lösung zufrieden. Ich werde eines Tages versuchen, meine Eingabeaufforderung zu bereinigen und zu überprüfen, ob die PIDs noch angezeigt werden.
Unode
Zsh-4.3.10, nachdem ich so ziemlich jede Anpassung deaktiviert habe, erhalte ich jetzt nicht mehr die Eingabeaufforderung (dh sie wurde ordnungsgemäß entfernt), aber ich erhalte immer noch die PIDs der Prozesse im Hintergrund, wie [1] 27911 27912in einer einzelnen Zeile und als erste Zeile in der Terminal.
Unode
Kann ich wieder upvoten? :) Es ist jetzt perfekt! Vielen Dank.
Unode