Criando uma barra de progresso no BASH, fixada na parte inferior do terminal

1

Eu fiz uma barra de progresso bem básica no BASH assim: -

doned=$1  #amount completed
total=$2  #total amount


doned='echo $doned $total | awk '{print ($1/$2)}''
total='tput cols | awk '{print $1-10}''
doned='echo $doned $total | awk '{print int(($1*$2))}''


echo -n $doned"% [ "

for i in $(seq 1 $doned); do
    echo -n "="
done

for i in $(seq $((doned+1)) $total); do
    echo -n "-"
done

echo " ]"

Isso funciona exatamente como eu quero.

Este script é executado dentro de um loop em outro script. Quero que ele seja sempre exibido na parte inferior do terminal ou em qualquer outro local fixo.

O loop é um pouco assim: -

for i in 10 20 30 40; do
    echo -n "Do you want to continue on to the next step? (y/n): ";
    read $yn
    if [[ "$yn" == "n" ]] || [[ "$yn" == "N" ]]; then
        exit 1; # stop the script
        d_3=0;
    fi
    doned='some command' ### Get number of completed files
    totalss='some other command' ### Get total number of files
    bash ./libraries/prog.sh $doned $totalss
done

Então, o que eu quero é que a barra de progresso permaneça na parte inferior mesmo ao inserir valores ou exibir algo. Existe uma maneira de fazer isso, de preferência sem ter que instalar nada extra? A maioria dos computadores em que eu quero usar este script é Debian versão 8+ ou sistemas Ubuntu 16+

    
por Yuki.kuroshita 12.09.2018 / 17:34

2 respostas

2

Talvez, mas acho que vai ser mais difícil do que você espera.

Você pode fazer o cursor se mover pelo terminal, emitindo códigos de controle ANSI. Para mais informações, consulte aqui .

Em princípio, você pode mover o cursor para sua barra de progresso, adicionar um = e, em seguida, movê-lo de volta para onde quer que você planeje imprimir a saída. Então no próximo = você teria que fazer de novo ... mas isso provavelmente seria feio.

Se você estiver disposto a se afastar do bash, provavelmente encontrará bibliotecas que facilitam esse tipo de coisa (como isto ).

    
por 12.09.2018 / 17:50
1

Eu escrevi um script de teste para tentar fazer o que o @MatrixManAtYrService sugeriu. Percebi que essa solução não se aplica a todos os sistemas cobertos pelo U & L SE, mas isso funciona dentro das especificações que solicitei.

#!/bin/bash

# go to last line and print the empty progress bar
tput sc #save the current cursor position
tput cup $(('tput lines'-1)) 3 # go to last line
echo -n "[" # the next 5 lines just print the required stuff to make the bar
for i in $(seq 1 $(('tput cols'-10))); do
    echo -n "-"
done
echo -n "]"
tput rc # bring the cursor back to the last saved position


# the actual loop which does the script's main job
for i in $(seq 0 10 100); do
    # print the filled progress bar
    tput sc  #save the current cursor position
    doned=${i}  #example value for completed amount
    total=100   #example value for total amount

    doned='echo $doned $total | awk '{print ($1/$2)}'' # the next three lines calculate how many characters to print for the completed amount
    total='tput cols | awk '{print $1-10}''
    doned='echo $doned $total | awk '{print int(($1*$2))}''


    tput cup $(('tput lines'-1)) 4 #go to the last line
    for l in $(seq 1 $doned); do #this loop prints the required no. of "="s to fill the bar
        echo -n "="
    done
    tput rc #bring the cursor back to the last saved position

    # the next 7 lines are to find the row on which the cursor is currently on to check if it 
    # is at the last line 
    # (based on the accepted answer of this question: https://stackoverflow.com/questions/2575037/)
    exec < /dev/tty
    oldstty=$(stty -g)
    stty raw -echo min 0
    tput u7 > /dev/tty
    IFS=';' read -r -d R -a pos
    stty $oldstty
    row=$((${pos[0]:2} - 1))


    # check if the cursor is on the line before the last line, if yes, clear the terminal, 
    # and make the empty bar again and fill it with the required amount of "="s
    if [ $row -gt $(('tput lines'-2)) ]; then
        clear
        tput sc
        tput cup $(('tput lines'-1)) 3
        echo -n "["

        for j in $(seq 1 $(('tput cols'-10))); do
            echo -n "-"
        done
        echo -n "]"
        tput cup $(('tput lines'-1)) 4
        for k in $(seq 1 $doned); do
            echo -n "="
        done
        tput rc
    fi

    # this is just to show that the cursor is behaving correctly
    read -p "Do you want to continue? (y/n)" yn;  

done

 # the next few lines remove the progress bar after the program is over   
tput sc # save the current cursor position
tput cup $(('tput lines'-1)) 3 # go to the line with the progress bar
tput el # clear the current line
tput rc # go back to the saved cursor position

Deve haver maneiras melhores de lidar com estouro na última linha, em vez de limpar o terminal, entre outras coisas. Isso serve mais como uma prova de conceito do que o @MatrixManAtYrService sugeriu. Quaisquer melhorias ou comentários sobre suas limitações são bem-vindos

    
por 12.09.2018 / 21:38