Pergunta

Sempre me perguntei como as pessoas atualizam uma linha anterior em uma linha de comando.um ótimo exemplo disso é ao usar o comando wget no Linux.Ele cria uma espécie de barra de carregamento ASCII semelhante a esta:

[======>                    ] 37%

e é claro que a barra de carregamento se move e a porcentagem muda, mas isso não cria uma nova linha.Não consigo descobrir como fazer isso.Alguém pode me apontar na direção certa?

Foi útil?

Solução

Existem duas maneiras que conheço de fazer isso:

  • Use o caractere de escape backspace ('\b') para apagar sua linha
  • Use o curses pacote, se a linguagem de programação de sua escolha tiver ligações para ele.

E um Google revelou Códigos de escape ANSI, o que parece ser um bom caminho.Para referência, aqui está uma função em C++ para fazer isso:

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

Outras dicas

Uma maneira de fazer isso é atualizar repetidamente a linha de texto com o progresso atual.Por exemplo:

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

Observe que eu usei sys.stdout.write em vez de print (isto é Python) porque print imprime automaticamente " " (nova linha de retorno de carro) no final de cada linha.Eu só quero o retorno de carro que retorna o cursor para o início da linha.Também o flush() é necessário porque, por padrão, sys.stdout apenas libera sua saída após uma nova linha (ou depois que seu buffer fica cheio).

O segredo é imprimir apenas em vez de ou no e da linha.

é chamado de retorno de carro e move o cursor no início da linha

n é chamado de alimentação de linha e move o cursor na próxima linha no console.Se você usar apenas você sobrescreve a linha escrita anteriormente.Então primeiro escreva uma linha como a seguinte:

[          ]

em seguida, adicione um sinal para cada tick

\r[=         ]

\r[==        ]

...

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

e assim por diante.Você pode usar 10 caracteres, cada um representando 10%.Além disso, se você quiser exibir uma mensagem quando terminar, não se esqueça de adicionar caracteres brancos suficientes para substituir os sinais de igual escritos anteriormente, assim:

\r[done      ]

abaixo está minha resposta, use a API do WindowsConsolas (Windows), codificação 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;
}

O PowerShell tem um cmdlet Write-Progress que cria uma barra de progresso no console que você pode atualizar e modificar à medida que seu script é executado.

Aqui está a resposta para sua pergunta...(Pitão)

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

Como acompanhamento A resposta de Greg, aqui está uma versão estendida de sua função que permite exibir mensagens multilinhas;basta passar uma lista ou tupla das strings que você deseja exibir/atualizar.

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

Observação:Eu testei isso apenas usando um terminal Linux, então sua milhagem pode variar em sistemas baseados em Windows.

Se você estiver usando uma linguagem de script, poderá usar o comando "tput cup" para fazer isso ...P.S.Até onde eu sei, isso é coisa de Linux/Unix...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top