[Bash] Construindo indicador de progresso

Leandro Nunes
Mar 26, 2018 · 5 min read

Atualmente tenho trabalhado bastante com shell e automação, então pretendo começar a escrever um pouco mais sobre o mundo no terminal e tentar trazer algumas coisas interessantes em Bash script que um Desenvolvedor Front-end acaba se perguntando como fazer para tentar trazer uma melhora na usabilidade dos scripts.

Image for post
Image for post
Bash is a Unix shell and command language

Hoje iremos ver como fazer um indicador de progresso, totalmente em Bash e sem nenhuma biblioteca externa, onde é possível utilizar em algum processo de instalação, ou em um processo demorado ou simplesmente para mostrar visualmente quantos comandos faltam a ser executado em determinada tarefa de forma que o usuário não fique esperando sem nenhum feedback.

No Bash uma das formas de exibirmos algo para o usuário é através do comando echo

#!/bin/bash
echo "Hello World!"
// Hello World!

E se fizermos dois echos seguidos, automaticamente é adicionado uma quebra de linha:

#!/bin/bash
echo "Hello"
echo "World!"
// Hello
// World!

Esse é o primeiro problema ao se pensar em um indicador de progresso, pois indicador de progresso não pode ficar pulando de linha:

Image for post
Image for post
log progressivo

O que queremos é algo próximo disso:

Image for post
Image for post
log indicador de progresso

Começando a programar

Para acompanhar os códigos a seguir, é só criar um progress.sh localmente e dar permissão de execução a ele com o comando chmod +x progress.sh.
Este comando só é necessário uma única vez, após isso, para executá-lo é só digitar ./progress.sh na linha de comando do terminal.

For..loop

Primeiro vamos fazer um loop com o comando for e colocar o nosso echo:

Image for post
Image for post
Bash online Compiler: http://rextester.com/FWY74472

Calculando a porcentagem

Agora que temos a sintaxe do for, vamos calcular e exibir a porcentagem ao invés do índice do loop.

Operações matemáticas no Bash, são feitos da seguinte forma:

#!/bin/bash
echo "$((2 + 2))"
// 4

Com isso já podemos então fazer nosso for..loop calculando a porcentagem em cada iteração do loop:

Image for post
Image for post
Bash online Compiler: http://rextester.com/YXID57940

Exibindo a barra de progresso

Agora vamos adicionar uma barra de progresso dentro dos colchetes com o caracter "#" conforme a variação da porcentagem. Para isso, precisamos saber como exibir uma parte de uma string. No JavaScript poderíamos fazer isso através do método substring por exemplo. No Bash, se eu quiser exibir apenas o meu primeiro nome, ficaria assim:

#!/bin/bash
declare -r name="Leandro Nunes"
echo "${name:0:7}"
// Leandro

Onde,
“:0” é o ponto de início
“:7” é o ponto de fim

Agora que vimos como fazer substring em Bash, podemos evoluir nosso código e adicionar uma barra visual de progresso da seguinte forma:

Image for post
Image for post
Bash online Compiler: http://rextester.com/LDFSW76492

Mantendo o log na mesma linha

Conseguimos até o momento fazer um log progressivo, porém o resultado final desejado é um log indicador de progresso e para isso falta conseguirmos manter todos os logs na mesma linha, dessa forma teremos uma atualização em cada loop e apenas o último estado será exibido.

Um detalhe sobre o comando echo é que ele não aceita por padrão caracteres especiais de controle, por exemplo, um simples \n :

#!/bin/bash
echo "Hello\nWorld!"
// Hello\nWorld!

O comando echo possui algumas flags especiais que adicionam "poder" a ele, e para o caso acima funcionar, temos que adicionar uma flag -e.

#!/bin/bash
echo -e "Hello\nWorld!"
// Hello
// World!

Outra flag que existe é -n e além do -e é exatamente essa que nos interessa. Pois ela mantém o ponteiro do curso na mesma linha, ou seja, ela não pula para a próxima linha ao executarmos dois echo seguidos.

#!/bin/bash
echo -n "Hello"
echo -n "World!"
// World!

Então vamos adicionar a flag -n e teremos o seguinte:

Image for post
Image for post
Bash online Compiler: http://rextester.com/SKNB80695

Observe que adicionei um sleep 1 na linha 13 para simular algum comando real que estivéssemos executando e obtermos um efeito de animação progressiva

As flags podem ser combinadas, então ao invés de usar apenas a flag -n iremos utilizar -ne desta forma além de manter na mesma linha, conseguiremos utilizar caracteres especial de controle e existe um que volta o ponteiro para o início da linha corrente \\r.

Image for post
Image for post
Bash online Compiler: http://rextester.com/VZRBW16090

Assim conseguimos o resultado esperado! 😃

Image for post
Image for post

Ops, quer dizer…
Conseguiu notar que não está exatamente igual a imagem que mostrei no inicio do post ? Percebe que temos um cursor aparecendo e quando chega no final exibe 100%% !?!!! 😕

Lapidando e finalização do resultado

Para esconder e exibir o cursor, temos o seguinte comando:

#!/bin/bash
# Esconde o cursor
tput civis -- invisible
# Volta cursor ao normal
tput cnorm -- normal

Para resolver o último caracter que fica estranho, é devido a flag -n que estamos utilizando, como ele mantém o cursos na mesma linha, qdo sai do programa e volta para o shell é inserido um caracter estranho, então basta adicionar um echo vazio após o loop e com isso o ponteiro volta ao estado normal. Então nosso código final fica assim:

Image for post
Image for post
http://rextester.com/JAGD20301

Resultado final !!!

Image for post
Image for post
log indicador de progresso

Veja outros exemplos de uso um pouco mais elaborados,
neste repositório do Github.

👋 Se curtiu o artigo, clique no “Clap” para aumentar a visibilidade do artigo!
-
Ajude a divulgar compartilhando
- Ajude a melhorar comentando
Qualquer dúvida ou sugestão me chame no Twitter (@lnfnunes)

Little abraços

Meninunes

Web Development by — Leandro “Little Big” Nunes

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store