Wie überschreibe ich stdout in C

Lesezeit: 4 Minuten

Scotts Benutzeravatar
Scott

In den meisten modernen Shells können Sie die Auf- und Abwärtspfeile drücken, und es werden an der Eingabeaufforderung frühere Befehle eingefügt, die Sie ausgeführt haben. Meine Frage ist, wie geht das?!

Es scheint mir, dass die Shell stdout irgendwie manipuliert, um zu überschreiben, was sie bereits geschrieben hat?

Mir ist aufgefallen, dass Programme wie wget dies auch tun. Hat jemand eine Ahnung, wie sie das machen?

Es manipuliert stdout nicht – es überschreibt die Zeichen, die bereits vom Terminal angezeigt wurden.

Versuche dies:

#include <stdio.h>
#include <unistd.h>
static char bar[] = "======================================="
                    "======================================>";
int main() {
    int i;
    for (i = 77; i >= 0; i--) {
        printf("[%s]\r", &bar[i]);
        fflush(stdout);
        sleep(1);
    }
    printf("\n");
    return 0;
}

Das ist ziemlich nah dran wget‘s Ausgabe, richtig? \r ist ein Wagenrücklauf, den das Terminal als “den Cursor zurück zum Anfang der aktuellen Zeile bewegt” interpretiert.

Ihre Muschel, wenn es eine ist bashnutzt die GNU Readline-Bibliothekdas viel allgemeinere Funktionen bietet, einschließlich Erkennung von Terminaltypen, Verlaufsverwaltung, programmierbare Tastenzuordnungen usw.

Eine weitere Sache – im Zweifelsfall sind die Quellen für Ihr wget, Ihre Shell usw. verfügbar.

vladrs Benutzeravatar
vladr

Um die aktuelle Standardausgabezeile (oder Teile davon) zu überschreiben, verwenden Sie \r (oder \b.) Das Sonderzeichen \r (Wagenrücklauf) setzt das Caretzeichen an den Anfang der Zeile zurück, sodass Sie es überschreiben können. Der besondere Charakter \b bringt das Caretzeichen nur um eine Position zurück, sodass Sie das letzte Zeichen überschreiben können, z

#include <stdio.h>
#include <unistd.h>

int i;
const char progress[] = "|/-\\";

for (i = 0; i < 100; i += 10) {
  printf("Processing: %3d%%\r",i); /* \r returns the caret to the line start */
  fflush(stdout);
  sleep(1);
}
printf("\n"); /* goes to the next line */
fflush(stdout);

printf("Processing: ");
for (i = 0; i < 100; i += 10) {
  printf("%c\b", progress[(i/10)%sizeof(progress)]); /* \b goes one back */
  fflush(stdout);
  sleep(1);
}
printf("\n"); /* goes to the next line */
fflush(stdout);

Verwenden fflush(stdout); Weil Die Standardausgabe wird normalerweise gepuffert und die Informationen dürfen ansonsten nicht sofort auf der Ausgabe oder dem Terminal gedruckt werden

  • Vielleicht möchten Sie ein #include für die Sleep-Funktion hinzufügen.

    – Präriedogg

    7. September 2010 um 1:58 Uhr

Sehen Sie sich zusätzlich zu \r und \b auch an ncurses für eine erweiterte Kontrolle darüber, was auf dem Konsolenbildschirm angezeigt wird. (Einschließlich Spalten, willkürliches Bewegen usw.).

Ein Programm, das in einem Textterminal / einer Konsole läuft, kann den in seiner Konsole angezeigten Text auf verschiedene Arten manipulieren (Text fett machen, Cursor bewegen, Bildschirm löschen usw.). Dies wird durch Drucken von speziellen Zeichenfolgen erreicht, die als bezeichnet werden “Escape-Sequenzen” (weil sie normalerweise mit Escape, ASCII 27 beginnen).

Wenn stdout zu einem Terminal geht, das diese Escape-Sequenzen versteht, ändert sich die Anzeige des Terminals entsprechend.

Wenn Sie stdout in eine Datei umleiten, werden die Escape-Sequenzen in der Datei angezeigt (was normalerweise nicht das ist, was Sie wollen).

Es gibt keinen vollständigen Standard für Escape-Sequenzen, aber die meisten Terminals verwenden die von eingeführten Sequenzen VT100, mit vielen Erweiterungen. Das verstehen die meisten Terminals unter Unix/Linux (xterm, rxvt, konsole) und andere wie PuTTY.

In der Praxis würden Sie Escape-Sequenzen nicht direkt in Ihre Software einprogrammieren (obwohl Sie könnten), sondern eine Bibliothek verwenden, um sie zu drucken, wie z ncurses oder GNU-Lesezeile oben erwähnt. Dies ermöglicht die Kompatibilität mit verschiedenen Endgerätetypen.

Es ist fertig mit der Zeile lesen Bibliothek … Ich bin mir nicht sicher, wie es hinter den Kulissen funktioniert, aber ich glaube nicht, dass es etwas mit stdout oder Streams zu tun hat. Ich vermute, dass readline (zumindest für mich) kryptische Terminalbefehle verwendet – das heißt, es kooperiert mit dem Terminalprogramm, das Ihre Shell-Sitzung tatsächlich anzeigt. Ich weiß nicht, dass Sie ein Readline-ähnliches Verhalten erhalten können, indem Sie einfach die Ausgabe drucken.

(Denken Sie darüber nach: stdout kann in eine Datei umgeleitet werden, aber der Trick mit den Pfeiltasten nach oben/unten funktioniert nicht bei Dateien.)

Benutzeravatar von Kknd
Kknd

Sie können dies mit Wagenrücklauf simulieren.

#include <stdio.h>

int main(int argc, char* argv[])
{
    while(1)
    {
        printf("***********");
        fflush(stdout);
        sleep(1);
        printf("\r");
        printf("...........");
        sleep(1);
    }

    return 0;
}

Das Programm tut dies, indem es Sonderzeichen druckt, die das Terminal auf besondere Weise interpretiert. Die einfachste Version davon ist (auf den meisten Linux/Unix-Terminals), ‘\r’ (Wagenrücklauf) in die normale Standardausgabe zu drucken, wodurch die Cursorposition auf das erste Zeichen in der aktuellen Zeile zurückgesetzt wird. Das, was Sie als nächstes schreiben, überschreibt also die Zeile, die Sie zuvor geschrieben haben. Dies kann beispielsweise für einfache Fortschrittsanzeigen verwendet werden.

int i = 0;
while (something) {
  i++;
  printf("\rprocessing line %i...", i);
  ...
}

Aber es gibt kompliziertere Escape-Zeichenfolgen, die auf verschiedene Weise interpretiert werden. Damit lassen sich alle möglichen Dinge erledigen, wie zum Beispiel das Positionieren des Cursors an einer bestimmten Position auf dem Bildschirm oder das Einstellen der Textfarbe. Ob oder wie diese Zeichenfolgen interpretiert werden, hängt von Ihrem Terminal ab, aber eine gemeinsame Klasse, die von den meisten Terminals unterstützt wird ansi-Escape-Sequenzen. Wenn Sie also roten Text möchten, versuchen Sie Folgendes:

printf("Text in \033[1;31mred\033[0m\n");

  • It’s not the shell that processes these special characters, it’s the terminal the shell is running in, i.e. an instance of xterm, rxvt, konsole or similar.

    – sleske

    Mar 18, 2009 at 0:53

1386320cookie-checkWie überschreibe ich stdout in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy