Pregunta Cómo animar la línea de comando?


Siempre me he preguntado cómo las personas actualizan una línea anterior en una línea de comando. un gran ejemplo de esto es cuando se usa el comando wget en Linux. Crea una especie de barra de carga ASCII que se ve así:

[======>] 37%

y, por supuesto, la barra de carga se mueve y el porcentaje cambia, pero no forma una nueva línea. No puedo encontrar la manera de hacer esto. ¿Alguien me puede apuntar en la dirección correcta?


76
2017-09-13 00:53


origen


Respuestas:


Hay dos formas en que sé hacer esto:

  • Usa el carácter de escape de retroceso ('\ b') para borrar tu línea
  • Utilizar el curses paquete, si su lenguaje de programación de elección tiene enlaces para ello.

Y un Google revelado Códigos de escape ANSI, que parece ser una buena manera. Como referencia, aquí hay una función en C ++ para hacer esto:

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.
}

42
2017-09-13 00:56



Una forma de hacerlo es actualizar varias veces la línea de texto con el progreso actual. Por ejemplo:

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

Tenga en cuenta que utilicé sys.stdout.write en lugar de print (esto es Python) porque print imprime automáticamente "\ r \ n" (carriage-return new-line) al final de cada línea. Solo quiero el retorno de carro que devuelve el cursor al inicio de la línea. También el flush() es necesario porque de forma predeterminada, sys.stdout solo vacía su salida después de una nueva línea (o después de que su buffer se llena).


56
2017-09-13 00:58



El secreto es imprimir solamente \ r en lugar de \ n o \ r \ n en el y de la línea.

se llama retorno de carro y mueve el cursor al inicio de la línea

\ n se llama alimentación de línea y mueve el cursor en la siguiente línea En la consola Si solo usa \ r sobrescribe la línea escrita anteriormente. Entonces, primero escribe una línea como la siguiente:

[          ]

luego agrega un letrero para cada tic

\r[=         ]

\r[==        ]

...

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

y así. Puedes usar 10 caracteres, cada uno representa un 10%. Además, si desea mostrar un mensaje cuando haya terminado, no olvide agregar también suficientes caracteres blancos para sobrescribir los signos iguales escritos previamente así:

\r[done      ]

13
2017-10-06 15:04



a continuación está mi respuesta, use la API de WindowsConsolas (Windows), codificación de 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;
}

4
2017-12-06 06:47



PowerShell tiene un cmdlet Write-Progress que crea una barra de progreso dentro de la consola que puede actualizar y modificar a medida que se ejecuta su secuencia de comandos.


3
2017-09-13 01:10



Aquí está la respuesta para su pregunta ... (Python)

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")

3
2017-07-04 09:12



Como seguimiento de La respuesta de Greg, aquí hay una versión extendida de su función que le permite mostrar mensajes de varias líneas; simplemente pase una lista o tupla de las cadenas que desea mostrar / actualizar.

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: Solo he probado esto usando un terminal de Linux, por lo que su kilometraje puede variar en los sistemas basados ​​en Windows.


2
2018-06-23 22:44



Si usa un lenguaje de scripting, puede usar el comando "tput cup" para hacer esto ... PD Esto es algo de Linux / Unix solo por lo que sé ...


0
2017-10-24 18:55