Ao criar scripts no bash ou em qualquer outro shell no * NIX, enquanto executa um comando que leva mais de alguns segundos, é necessária uma barra de progresso.
Por exemplo, copiando um arquivo grande, abrindo um arquivo tar grande.
De que maneiras você recomenda adicionar barras de progresso aos shell scripts?
Respostas:
Você pode implementar isso substituindo uma linha. Use
\r
para voltar ao início da linha sem escrever\n
no terminal.Escreva
\n
quando terminar para avançar na linha.Use
echo -ne
para:\n
e\r
.Aqui está uma demonstração:
Em um comentário abaixo, puk menciona isso "falha" se você começar com uma linha longa e depois escrever uma linha curta: Nesse caso, você precisará sobrescrever o comprimento da linha longa (por exemplo, com espaços).
fonte
printf
vez deecho
.printf "#### (50%%)\r"
ele não funcionaria com aspas simples e o sinal de porcentagem precisa ser escapado.Você também pode estar interessado em como fazer um girador :
Posso fazer um spinner no Bash?
fonte
while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done
(*:sleep
pode exigir ints em vez de decimais)some_work ...
linha acima; uma discussão mais detalhada que se baseia nesta resposta útil e o comentário útil de Adam Katz - com foco na conformidade com POSIX - podem ser encontrados aqui .\b
vez de\r
, pois, caso contrário, funcionará apenas no início de uma linha:while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done
- ou, se o cursor for exibido por trás do botão giratório é indesejável:printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
job=$!
) e, em seguidawhile kill -0 $job 2>/dev/null;do …
, executar , por exemplo:sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
Algumas postagens mostraram como exibir o progresso do comando. Para calculá-lo, você precisará ver quanto progrediu. Nos sistemas BSD, alguns comandos, como dd (1), aceitam um
SIGINFO
sinal e relatam seu progresso. Nos sistemas Linux, alguns comandos respondem da mesma formaSIGUSR1
. Se esse recurso estiver disponível, você poderá canalizar sua entradadd
para monitorar o número de bytes processados.Como alternativa, você pode usar
lsof
para obter o deslocamento do ponteiro de leitura do arquivo e, assim, calcular o progresso. Eu escrevi um comando, chamado pmonitor , que exibe o progresso do processamento de um processo ou arquivo especificado. Com ele, você pode fazer coisas como as seguintes.Uma versão anterior dos scripts de shell do Linux e FreeBSD aparece no meu blog .
fonte
awk
em jogo!Tenho uma função de barra de progresso fácil que escrevi no outro dia:
Ou então,
https://github.com/fearside/ProgressBar/
fonte
printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
use o comando linux pv:
http://linux.die.net/man/1/pv
ele não sabe o tamanho se estiver no meio do fluxo, mas fornece velocidade e total e, a partir daí, você pode descobrir quanto tempo deve levar e obter feedback para saber que não parou.
fonte
Eu estava procurando por algo mais sexy que a resposta selecionada, assim como meu próprio script.
Pré-visualização
Fonte
Eu coloquei no github
progress-bar.sh
Uso
fonte
progress-bar 100
Alcatrão GNU tem uma opção útil que fornece a funcionalidade de uma barra de progresso simples.
(...) Outra ação de ponto de verificação disponível é 'ponto' (ou '.'). Ele instrui o tar a imprimir um único ponto no fluxo de listagem padrão, por exemplo:
O mesmo efeito pode ser obtido por:
fonte
--checkpoint=.10
. Também funciona muito bem ao extrair comtar -xz
.Um método mais simples que funciona no meu sistema usando o utilitário pipeview (pv).
fonte
Não vi nada parecido e todas as funções personalizadas aqui parecem se concentrar apenas na renderização, então ... minha solução muito simples compatível com POSIX abaixo, com explicações passo a passo, porque esta pergunta não é trivial.
TL; DR
Renderizar a barra de progresso é muito fácil. Estimar quanto dele deve render é uma questão diferente. Eis como renderizar (animar) a barra de progresso - você pode copiar e colar este exemplo em um arquivo e executá-lo:
{1..20}
- valores de 1 a 20echo -n
- imprima sem nova linha no finalecho -e
- interpretar caracteres especiais durante a impressão"\r"
- retorno de carro, um caractere especial para retornar ao início da linhaVocê pode fazer com que qualquer conteúdo seja processado a qualquer velocidade, para que esse método seja muito universal, por exemplo, frequentemente usado para visualização de "hackers" em filmes tolos, sem brincadeira.
Resposta completa
A questão do problema é como determinar o
$i
valor, ou seja, quanto da barra de progresso deve ser exibida. No exemplo acima, deixei que ele aumentasse emfor
loop para ilustrar o princípio, mas um aplicativo da vida real usaria um loop infinito e calcularia a$i
variável em cada iteração. Para fazer esse cálculo, ele precisa dos seguintes ingredientes:Caso
cp
precise do tamanho de um arquivo de origem e do tamanho do arquivo de destino:stat
- verificar estatísticas do arquivo-c
- retornar valor formatado%s
- tamanho totalNo caso de operações como descompactação de arquivo, calcular o tamanho da fonte é um pouco mais difícil, mas ainda tão fácil quanto obter o tamanho de um arquivo descompactado:
gzip -l
- exibir informações sobre o arquivo ziptail -n1
- trabalhe com 1 linha a partir do fundotr -s ' '
- traduza vários espaços para um (aperte-os)cut -d' ' -f3
- cortar a terceira coluna delimitada por espaçoAqui está a carne do problema, no entanto. Esta solução é cada vez menos geral. Todos os cálculos do progresso real estão fortemente vinculados ao domínio que você está tentando visualizar: é uma operação de arquivo único, uma contagem regressiva do temporizador, um número crescente de arquivos em um diretório, operação em vários arquivos etc. não pode ser reutilizado. A única parte reutilizável é a renderização da barra de progresso. Para reutilizá-lo, você precisa abstraí-lo e salvá-lo em um arquivo (por exemplo
/usr/lib/progress_bar.sh
) e, em seguida, definir funções que calculam valores de entrada específicos para seu domínio. É assim que um código generalizado pode parecer (eu também fiz o$BAR
dinamizei porque as pessoas estavam pedindo por ele, o resto deve estar claro agora):printf
- um built-in para imprimir coisas em um determinado formatoprintf '%50s'
- imprima nada, cubra-o com 50 espaçostr ' ' '#'
- traduza todo espaço para sinal de hashE é assim que você usaria:
Obviamente, ele pode ser envolvido em uma função, reescrita para trabalhar com fluxos canalizados, reescrita para outra linguagem, qualquer que seja o seu veneno.
fonte
Eu também gostaria de contribuir com minha própria barra de progresso
Atinge precisão de sub-caracteres usando blocos Half unicode
O código está incluído
fonte
Barra de progresso do estilo APT (não interrompe a saída normal)
EDIT: Para uma versão atualizada, verifique minha página do github
Eu não estava satisfeito com as respostas sobre esta questão. O que eu procurava pessoalmente era uma barra de progresso sofisticada, como é visto pelo APT.
Eu dei uma olhada no código-fonte C do APT e decidi escrever meu próprio equivalente para o bash.
Essa barra de progresso permanecerá bem na parte inferior do terminal e não interferirá em nenhuma saída enviada ao terminal.
Observe que a barra está atualmente fixa em 100 caracteres. Se você deseja dimensioná-lo para o tamanho do terminal, isso também é bastante fácil de realizar (a versão atualizada na minha página do github lida com isso).
Vou postar meu script aqui. Exemplo de uso:
O script (eu recomendo fortemente a versão no meu github):
fonte
Isso permite visualizar que um comando ainda está sendo executado:
Isso criará um loop while infinito que é executado em segundo plano e ecoa um "." todo segundo. Isso será exibido
.
no shell. Execute otar
comando ou qualquer comando que desejar. Quando esse comando terminar de executar, mate o último trabalho em execução em segundo plano - que é o loop while infinito .fonte
Aqui está como pode parecer
Fazendo upload de um arquivo
Aguardando a conclusão de um trabalho
Função simples que o implementa
Você pode simplesmente copiar e colar no seu script. Não requer mais nada para funcionar.
Exemplo de uso
Aqui, fazemos upload de um arquivo e redesenhamos a barra de progresso a cada iteração. Não importa qual trabalho é realmente executado, desde que possamos obter 2 valores: valor máximo e valor atual.
No exemplo abaixo, o valor máximo é
file_size
e o valor atual é fornecido por alguma função e é chamadouploaded_bytes
.fonte
A maioria dos comandos unix não fornece o tipo de feedback direto a partir do qual você pode fazer isso. Alguns fornecerão a saída no stdout ou stderr que você pode usar.
Para algo como tar, você pode usar a opção -v e canalizar a saída para um programa que atualiza uma pequena animação para cada linha que lê. À medida que o tar escreve uma lista de arquivos, é revelado que o programa pode atualizar a animação. Para completar uma porcentagem, você precisa saber o número de arquivos e contar as linhas.
O cp não fornece esse tipo de saída até onde eu sei. Para monitorar o progresso do cp, é necessário monitorar os arquivos de origem e destino e observar o tamanho do destino. Você pode escrever um pequeno programa c usando a chamada de sistema stat (2) para obter o tamanho do arquivo. Isso leria o tamanho da fonte, pesquisaria o arquivo de destino e atualizaria uma barra% concluída com base no tamanho do arquivo gravado até a data.
fonte
Minha solução exibe a porcentagem do tarball que está sendo descompactado e gravado. Eu uso isso ao escrever imagens de sistema de arquivos raiz de 2 GB. Você realmente precisa de uma barra de progresso para essas coisas. O que eu faço é usar
gzip --list
para obter o tamanho total não compactado do tarball. A partir disso, calculo o fator de bloqueio necessário para dividir o arquivo em 100 partes. Por fim, imprimo uma mensagem de ponto de verificação para cada bloco. Para um arquivo de 2 GB, isso dá cerca de 10 MB por bloco. Se isso for muito grande, você poderá dividir o BLOCKING_FACTOR por 10 ou 100, mas será mais difícil imprimir uma saída bonita em termos de porcentagem.Supondo que você esteja usando o Bash, poderá usar a seguinte função shell
fonte
Antes de tudo, a barra não é o único medidor de progresso de um tubo. O outro (talvez ainda mais conhecido) é o pv (visualizador de tubos).
Em segundo lugar, bar e pv podem ser usados, por exemplo, assim:
ou até:
Um truque útil se você quiser usar os comandos bar e pv em comandos que estão trabalhando com arquivos fornecidos em argumentos, como, por exemplo, copiar arquivo1 arquivo2, é usar a substituição de processo :
A substituição de processo é uma coisa mágica do bash que cria arquivos temporários do canal fifo / dev / fd / e conecta o stdout do processo executado (entre parênteses) através desse canal e a cópia o vê como um arquivo comum (com uma exceção, ele só pode lê-lo para a frente).
Atualizar:
O próprio comando bar também permite copiar. Depois da barra de homem:
Mas, na minha opinião, a substituição de processos é uma maneira mais genérica de fazê-lo. E ele usa o próprio programa cp.
fonte
Eu prefiro usar o diálogo com o parâmetro --gauge . É usado com muita frequência em instalações de pacotes .deb e outros itens básicos de configuração de muitas distribuições. Então você não precisa reinventar a roda ... de novo
Basta colocar um valor int de 1 a 100 @stdin. Um exemplo básico e bobo:
Eu tenho este arquivo / bin / Wait (com chmod u + x perms) para fins de culinária: P
Então eu posso colocar:
Wait "34 min" "warm up the oven"
ou
Wait "dec 31" "happy new year"
fonte
para mim, mais fácil de usar e mais bonito até agora é comando
pv
oubar
como um cara já escreveupor exemplo: é necessário fazer um backup de toda a unidade com
dd
normalmente você usa
dd if="$input_drive_path" of="$output_file_path"
com
pv
você pode fazer assim:dd if="$input_drive_path" | pv | dd of="$output_file_path"
e o progresso vai diretamente para
STDOUT
o seguinte:depois que é feito resumo aparece
fonte
pv
oubar
visualizar o progresso de diferentes processos, por exemplo, contagem regressiva do temporizador, posição em um arquivo de texto, instalação do aplicativo, configuração do tempo de execução, etc.?Muitas respostas descrevem a gravação de seus próprios comandos para impressão
'\r' + $some_sort_of_progress_msg
. O problema às vezes é que imprimir centenas dessas atualizações por segundo atrasará o processo.No entanto, se algum de seus processos produzir saída (por exemplo
7z a -r newZipFile myFolder
, produzirá cada nome de arquivo à medida que o compacta), existe uma solução mais simples, rápida, indolor e personalizável.Instale o módulo python
tqdm
.Ajuda:
tqdm -h
. Um exemplo usando mais opções:Como bônus, você também pode usar
tqdm
para agrupar iterables no código python.https://github.com/tqdm/tqdm/blob/master/README.rst#module
fonte
tqdm
STDOUTwc -l
através de um cano. Você provavelmente quer escapar disso.tqdm
vai mostrar o progresso emSTDERR
enquanto tubulação sua entradaSTDIN
paraSTDOUT
. Nesse caso,wc -l
receberia a mesma entrada como setqdm
não estivesse incluída.Com base no trabalho de Edouard Lopez, criei uma barra de progresso que se ajusta ao tamanho da tela, seja ela qual for. Confira.
Também está publicado no Git Hub .
Aproveitar
fonte
https://github.com/extensionsapp/progre.sh
Crie 40% de progresso:
progreSh 40
fonte
Isso é aplicável apenas usando o zenity do gnome. O Zenity fornece uma ótima interface nativa para bash scripts: https://help.gnome.org/users/zenity/stable/
Exemplo de barra de progresso do Zenity:
fonte
Eu usei uma resposta de Criando seqüência de caracteres repetidos no shell script para repetição de caracteres. Eu tenho duas versões bash relativamente pequenas para scripts que precisam exibir a barra de progresso (por exemplo, um loop que passa por muitos arquivos, mas não é útil para arquivos tar grandes ou operações de cópia). O mais rápido consiste em duas funções, uma para preparar as strings para exibição de barra:
e um para exibir uma barra de progresso:
Pode ser usado como:
o que significa preparar seqüências de caracteres para a barra com 50 caracteres "#" e depois:
exibirá o número de caracteres "#" que corresponde à proporção 35/80:
Esteja ciente de que a função exibe a barra na mesma linha repetidamente até que você (ou algum outro programa) imprima uma nova linha. Se você colocar -1 como primeiro parâmetro, a barra será apagada:
A versão mais lenta é tudo em uma função:
e pode ser usado como (o mesmo exemplo acima):
Se você precisar da barra de progresso no stderr, basta adicionar
>&2
no final de cada comando printf.fonte
Para indicar o progresso da atividade, tente os seguintes comandos:
OU
OU
OU
Pode-se usar sinalizadores / variáveis dentro do loop while para verificar e exibir o valor / extensão do progresso.
fonte
Usando as sugestões listadas acima, decidi implementar minha própria barra de progresso.
fonte
percent_none="$(( 100 - "$percent_done" ))"
parapercent_none="$(( 100 - $percent_done))"
Eu fiz uma versão pura do shell para um sistema embarcado aproveitando:
Recurso de manipulação de sinal SIGUSR1 do / usr / bin / dd.
Basicamente, se você enviar um 'kill SIGUSR1 $ (pid_of_running_dd_process)', ele exibirá um resumo da velocidade de transferência e da quantidade transferida.
fazendo o background do dd e consultando-o regularmente para atualizações, e gerando hash ticks como costumavam os clientes ftp da velha escola.
Usando / dev / stdout como destino para programas amigáveis não stdout como scp
O resultado final permite que você faça qualquer operação de transferência de arquivos e obtenha atualizações de progresso que se parecem com a saída 'hash' do FTP da velha escola, onde você apenas obteria uma marca de hash para cada X bytes.
Isso dificilmente é um código de qualidade de produção, mas você entendeu. Eu acho fofo.
Pelo que vale, a contagem de bytes real pode não ser refletida corretamente no número de hashes - você pode ter um mais ou menos, dependendo dos problemas de arredondamento. Não use isso como parte de um script de teste, é apenas um colírio para os olhos. E, sim, sei que isso é terrivelmente ineficiente - é um script de shell e não peço desculpas por isso.
Exemplos com wget, scp e tftp fornecidos no final. Deve funcionar com qualquer coisa que emita dados. Certifique-se de usar / dev / stdout para programas que não são compatíveis com o stdout.
Exemplos:
fonte
pidof dd
é assustador.$!
a partirdd
e esperar[[ -e /proc/${DD_PID} ]]
.Caso você precise mostrar uma barra de progresso temporal (sabendo antecipadamente o horário da exibição), você pode usar o Python da seguinte maneira:
Supondo que você tenha salvo o script Python como
progressbar.py
, é possível mostrar a barra de progresso do script bash executando o seguinte comando:Ele mostraria uma barra de progresso do tamanho de
50
caracteres e "em execução" por10
segundos.fonte
Eu desenvolvi a resposta fornecida pelo medo
Isso se conecta a um banco de dados Oracle para recuperar o progresso de uma restauração do RMAN.
fonte
poderia criar uma função que desenha isso em uma escala, digamos 1 a 10 para o número de barras:
fonte
resultado:
nota: se em vez de 255 você colocar 1, monitorará o padrão em ... com 2 o padrão (mas você deve modificar a fonte para definir "tot" no tamanho do arquivo de saída projetado)
fonte