Domanda

Mi sono sempre chiesto come le persone aggiornano una riga precedente in una riga di comando.un ottimo esempio di ciò è quando si utilizza il comando wget in Linux.Crea una sorta di barra di caricamento ASCII simile a questa:

[======>                    ] 37%

e ovviamente la barra di caricamento si sposta e la percentuale cambia, ma non crea una nuova riga.Non riesco a capire come farlo.Qualcuno può indicarmi la giusta direzione?

È stato utile?

Soluzione

Ci sono due modi che conosco per farlo:

  • Utilizza il carattere di escape backspace ('\b') per cancellare la riga
  • Usa il curses package, se il tuo linguaggio di programmazione preferito ha dei collegamenti per esso.

E un Google ha rivelato Codici di fuga ANSI, che sembra essere un buon modo.Per riferimento, ecco una funzione in C++ per fare ciò:

void DrawProgressBar(int len, double percent) {
  cout << "\x1B[2K"; // Erase the entire current line.
  cout << "\x1B[0E"; // Move to the beginning of the current line.
  string progress;
  for (int i = 0; i < len; ++i) {
    if (i < static_cast<int>(len * percent)) {
      progress += "=";
    } else {
      progress += " ";
    }
  }
  cout << "[" << progress << "] " << (static_cast<int>(100 * percent)) << "%";
  flush(cout); // Required.
}

Altri suggerimenti

Un modo per farlo è aggiornare ripetutamente la riga di testo con l'avanzamento corrente.Per esempio:

def status(percent):
    sys.stdout.write("%3d%%\r" % percent)
    sys.stdout.flush()

Nota che ho usato sys.stdout.write invece di print (questo è Python) perché print stampa automaticamente " " (ritorno a capo di nuova riga) alla fine di ogni riga.Voglio solo il ritorno a capo che riporta il cursore all'inizio della riga.Anche il flush() è necessario perché per impostazione predefinita, sys.stdout scarica il suo output solo dopo una nuova riga (o dopo che il buffer è pieno).

Il segreto è stampare solo invece di o alla fine della riga.

si chiama ritorno a capo e sposta il cursore all'inizio della riga

N si chiama feed di linea e sposta il cursore sulla riga successiva nella console.Se usi solo sovrascrivi la riga scritta in precedenza.Quindi prima scrivi una riga come la seguente:

[          ]

quindi aggiungi un segno per ogni segno di spunta

\r[=         ]

\r[==        ]

...

\r[==========]

e così via.Puoi utilizzare 10 caratteri, ciascuno dei quali rappresenta un 10%.Inoltre, se vuoi visualizzare un messaggio al termine, non dimenticare di aggiungere anche abbastanza caratteri bianchi in modo da sovrascrivere i segni di uguale precedentemente scritti in questo modo:

\r[done      ]

di seguito è la mia risposta, utilizza l'API di WindowsConsole (Windows), codifica di C.

/*
* file: ProgressBarConsole.cpp
* description: a console progress bar Demo
* author: lijian <hustlijian@gmail.com>
* version: 1.0
* date: 2012-12-06
*/
#include <stdio.h>
#include <windows.h>

HANDLE hOut;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
char charProgress[80] = 
    {"================================================================"};
char spaceProgress = ' ';

/*
* show a progress in the [row] line
* row start from 0 to the end
*/
int ProgressBar(char *task, int row, int progress)
{
    char str[100];
    int len, barLen,progressLen;
    COORD crStart, crCurr;
    GetConsoleScreenBufferInfo(hOut, &bInfo);
    crCurr = bInfo.dwCursorPosition; //the old position
    len = bInfo.dwMaximumWindowSize.X;
    barLen = len - 17;//minus the extra char
    progressLen = (int)((progress/100.0)*barLen);
    crStart.X = 0;
    crStart.Y = row;

    sprintf(str,"%-10s[%-.*s>%*c]%3d%%", task,progressLen,charProgress, barLen-progressLen,spaceProgress,50);
#if 0 //use stdand libary
    SetConsoleCursorPosition(hOut, crStart);
    printf("%s\n", str);
#else
    WriteConsoleOutputCharacter(hOut, str, len,crStart,NULL);
#endif
    SetConsoleCursorPosition(hOut, crCurr);
    return 0;
}
int main(int argc, char* argv[])
{
    int i;
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(hOut, &bInfo);

    for (i=0;i<100;i++)
    {
        ProgressBar("test", 0, i);
        Sleep(50);
    }

    return 0;
}

PowerShell dispone di un cmdlet Write-Progress che crea una barra di avanzamento nella console che puoi aggiornare e modificare durante l'esecuzione dello script.

Ecco la risposta alla tua domanda...(pitone)

def disp_status(timelapse, timeout):
  if timelapse and timeout:
     percent = 100 * (float(timelapse)/float(timeout))
     sys.stdout.write("progress : ["+"*"*int(percent)+" "*(100-int(percent-1))+"]"+str(percent)+" %")
     sys.stdout.flush()
     stdout.write("\r  \r")

Come seguito a La risposta di Greg, ecco una versione estesa della sua funzione che permette di visualizzare messaggi su più righe;basta passare un elenco o una tupla delle stringhe che desideri visualizzare/aggiornare.

def status(msgs):
    assert isinstance(msgs, (list, tuple))

    sys.stdout.write(''.join(msg + '\n' for msg in msgs[:-1]) + msgs[-1] + ('\x1b[A' * (len(msgs) - 1)) + '\r')
    sys.stdout.flush()

Nota:L'ho testato solo utilizzando un terminale Linux, quindi il tuo chilometraggio può variare sui sistemi basati su Windows.

Se usi un linguaggio di scripting potresti usare il comando "tput cup" per farlo...PSQuesta è una cosa Linux/Unix solo per quanto ne so...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top