BASH 터미널 하단에 고정 진행률 표시줄 만들기

BASH 터미널 하단에 고정 진행률 표시줄 만들기

아래와 같이 BASH에서 매우 기본적인 진행률 표시줄을 만들었습니다.

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

이것은 내가 원하는 방식으로 정확하게 작동합니다.

이 스크립트는 다른 스크립트의 루프 내에서 실행됩니다. 터미널 하단이나 기타 고정된 위치에 항상 표시되기를 원합니다.

루프는 다음과 같습니다.

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

그래서 제가 원하는 것은 값을 입력하거나 무언가가 표시되는 경우에도 진행률 표시줄이 하단에 유지되는 것입니다. 추가로 설치하지 않고 이 작업을 수행할 수 있는 방법이 있습니까? 이 스크립트를 사용하려는 대부분의 컴퓨터는 Debian 버전 8+ 또는 Ubuntu 16+ 시스템입니다.

답변1

@MatrixManAtYrService가 제안한 작업을 수행하기 위해 테스트 스크립트를 작성했습니다. 나는 이 솔루션이 U&L SE가 적용되는 모든 시스템에서 작동하지 않는다는 것을 알고 있지만 이것이 내가 요구하는 사양을 충족합니다.

#!/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

터미널을 지우는 것보다 마지막 줄의 오버플로를 처리하는 더 좋은 방법이 있어야 합니다. 이는 @MatrixManAtYrService가 제안한 개념 증명에 가깝습니다. 제한 사항에 대한 개선 사항이나 의견을 환영합니다.

답변2

그럴지도 모르지만 생각보다 어려울 것 같아요.

ANSI 제어 코드를 출력하여 터미널의 커서를 이동할 수 있습니다. 이에 대한 자세한 내용은 다음을 참조하세요.여기.

원칙적으로 커서를 진행률 표시줄로 이동하여 추가한 =다음 출력을 인쇄하려는 위치로 다시 이동할 수 있습니다. 그러면 다음에 =다시 해야 하지만... 보기 흉할 수 있습니다.

bash에서 벗어나고 싶다면 아마도 이런 종류의 일을 더 쉽게 해주는 라이브러리를 찾을 수 있을 것입니다(예:이것).

답변3

쉘 스크립트에서 진행률 표시줄을 얻는 쉬운 방법은 주석에서 언급한 대로hiptail 또는 대화 상자를 사용하는 것입니다. 대부분의 Linux 배포판에서는 둘 중 하나 또는 둘 다를 사용할 수 있습니다.

OP는 의견에서 적성 설치 프로그램을 언급했습니다. Aptitude는 대화 상자와 마찬가지로 ncurses 라이브러리를 사용하는 바이너리입니다.

관련 정보