Crie uma barra de progresso no bash

13

Como posso criar uma barra de progresso com o bash?

Este é o meu script:

 #!/bin/bash
 pass='number1 number12 number13 number14 number15 number16'
 chk='number14'
 for i in $pass ; do
 if [ "$i" == "$chk" ]; then
 echo ' Found ^_^'
 else
 echo 'loading 50%'
 fi
 done

Eu quero substituir echo 'loading 50%' por qualquer coisa para criar uma barra de progresso.

    
por Black Hawk 17.03.2016 / 16:34

4 respostas

14

whiptail vem pré-instalado no Ubuntu e em muitas outras distros, e mostrará tela cheia (mas ainda assim terminal- base) elementos de progresso.

dialog é um superconjunto de whiptail , portanto, este exemplo funcionará igualmente bem com ambos. Ele fornece elementos de interface do usuário mais avançados, por isso pode ser útil se você estiver procurando interação do usuário, como seletores de arquivos e formulários, mas tem a desvantagem de não vir pré-instalado em muitos sistemas.

for i in $(seq 1 100)
do
    sleep 0.1 
    echo $i
done | whiptail --title 'Test script' --gauge 'Running...' 6 60 0

Observe que a saída do script é interpretada como uma porcentagem, portanto, talvez seja necessário ajustar a saída de acordo.

O Whiptail e o Dialog também permitem que você modifique o texto em tempo de execução por meio de uma sintaxe bastante críptica:

phases=( 
    'Locating Jebediah Kerman...'
    'Motivating Kerbals...'
    'Treating Kessler Syndrome...'
    'Recruiting Kerbals...'
)   

for i in $(seq 1 100); do  
    sleep 0.1

    if [ $i -eq 100 ]; then
        echo -e "XXX\n100\nDone!\nXXX"
    elif [ $(($i % 25)) -eq 0 ]; then
        let "phase = $i / 25"
        echo -e "XXX\n$i\n${phases[phase]}\nXXX"
    else
        echo $i
    fi 
done | whiptail --title 'Kerbal Space Program' --gauge "${phases[0]}" 6 60 0

pv mostra o progresso de um arquivo ou fluxo sendo canalizado através dele. No entanto, não pode ser (facilmente?) Usado para mostrar o progresso de uma operação personalizada, como um loop. Ele é projetado especificamente para fluxos.

$ head -c 1G < /dev/urandom | pv -s 1G > /dev/null
 277MB 0:00:16 [17.4MB/s] [========>                           ] 27% ETA 0:00:43

Alguns exemplos do mundo real em que pv é útil:

# progress while importing a DB dump
pv mybigfile.sql | mysql -uroot -p dbname

# importing straight from a remote server
ssh user@server 'cat mybigfile.sql.gz' | pv | gzip -cd | mysql -uroot -p dbname

# taking a snapshot of a btrfs partition
btrfs send /snapshots/$date | pv | btrfs receive /mnt/backup/root

Não conheço nenhum comando que forneça barras de progresso de uma linha no estilo pv ou wget , mas há vários scripts simples de Bash / Perl / sed que adicionam essa funcionalidade, como os outros. compartilhei aqui.

    
por Mikkel 17.03.2016 / 18:14
6

Você pode usar zenity para criar janelas de diálogo simples do GTK. Uma das opções disponíveis é uma caixa de diálogo da barra de progresso.

Você cria essa janela usando zenity --progress . Para torná-lo útil, você deve especificar mais informações adicionando algumas das opções abaixo (trecho de man zenity ):

   Progress options
   --text=STRING
          Set the dialog text
   --percentage=INT
          Set initial percentage
   --auto-close
          Close dialog when 100% has been reached
   --auto-kill
          Kill parent process if cancel button is pressed
   --pulsate
          Pulsate progress bar
   --no-cancel
          Hides the cancel button

Existem dois modos:

  • pulsante : A barra de progresso está pulsando, apenas indica que algo está sendo executado, mas não diz nada sobre o progresso. Você faz isso configurando a opção --pulsating .

  • manual : você precisa canalizar a porcentagem atual de progresso para a entrada padrão do comando zenity para atualizar a barra de progresso.
    Um exemplo disso pode ser parecido com isso abaixo. Observe que os comandos anteriores são agrupados em uma sub-rede, de modo que toda a saída seja redirecionada para o diálogo zenity e não apenas para o último comando:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress
    
por Byte Commander 17.03.2016 / 16:58
4

Este código irá fazê-lo, e não requer nada (exceto bash, é claro). Ele imprime # sinais, como você pediu em seu comentário:

pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenProgressBar=${#passarr[@]}

echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '#\nFound ^_^'
        break
    else
        echo -n '#'
    fi
done

No entanto, se você tiver muito a verificar, isso apenas preencherá sua tela com # sinais. Para corrigir esse problema, tente este código:

lenProgressBar=5
pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenPass=${#passarr[@]}

if [ $lenProgressBar -gt $lenPass ]; then
    lenProgressBar=lenPass
elif [ $lenProgressBar -lt 1 ]; then
    lenProgressBar=1
fi

let "chksForEqualsPrint = $lenPass / $lenProgressBar"
echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
n=1

for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '\nFound ^_^'
        break
    else
        if [ $n -eq $chksForEqualsPrint ]; then
            echo -n '#'
            n=1
        else
            ((n++))
        fi
    fi
done

Altere os 5 na primeira linha ( lenProgressBar=5 ) para o comprimento que você deseja que sua barra de progresso seja. Levará mais tempo para imprimir um sinal # com barras de progresso de menor comprimento do que com as de maior comprimento, mas não deixe que a duração da barra de progresso exceda o tamanho da sua tela; não funcionará bem se você fizer. (Não permite usar uma barra de progresso maior que o número de itens que você está verificando ou menor que 1)

    
por insert_name_here 17.03.2016 / 19:09
0

Aqui está outra abordagem usando códigos de escape ansi:

#!/bin/bash

pass='number1 number2 number 3 number4 number12 number13 number14 number15 number16'
chk='number15'
result="Not Found!"

echo
echo -n "Working... "
echo -ne "3[1;32m3[7m3[?25l"

for i in $pass ; do
   sleep .4s
   if [ "$i" == "$chk" ]; then
      result="  Found ^_^"
      break
   else
      echo -n " "
   fi
done

echo -ne "\r3[0m3[K3[?25h"
echo $result
echo
    
por bashBedlam 21.07.2016 / 04:19