Bash - Clearing the last output correctly

后端 未结 2 1004
隐瞒了意图╮
隐瞒了意图╮ 2021-01-13 05:53

I\'m trying to create an update-able progress status. In order to do that, I need to be able to clear the last output in its entirety so that I can update it. Carriage retur

2条回答
  •  我在风中等你
    2021-01-13 06:06

    Something tricky

    Inspired by How to get the cursor position in bash?

    #!/bin/bash
    
    lineformat="This is a very long line with a lot of stuff so they will take " 
    lineformat+="more than standard terminal width (80) columns... Progress %3d%%" 
    
    n=0
    while [[ $n -ne 100 ]]; do
        n=$((n+1))
        printf -v outputstring "$lineformat" $n
        twidth=$(tput cols)      # Get terminal width
        theight=$(tput lines)    # Get terminal height
        oldstty=$(stty -g)       # Save stty settings
        stty raw -echo min 0     # Suppres echo on terminal
        # echo -en "\E[6n"
        tput u7                  # Inquire for cursor position
        read -sdR CURPOS         # Read cursor position
        stty $oldstty            # Restore stty settings
        IFS=\; read cv ch <<<"${CURPOS#$'\e['}" # split $CURPOS
        uplines=$(((${#outputstring}/twidth)+cv-theight))
        ((uplines>0)) &&
            tput cuu $uplines    # cursor up one or more lines
        tput ed                  # clear to end of screen
        tput sc                  # save cursor position
        echo -n "$outputstring"
        tput rc                  # restore cursor
        sleep .0331s
    done
    echo
    

    As tput cols and tput lines is initiated at each loop, you could resize window while running, cuu argument will be re-computed.

    More complex sample

    • Using trap WINCH for querying terminal size only when window is resized
    • Addind newlines for scrolling up before cuu
    • Reducing forks to tput

    There:

    #!/bin/bash
    
    lineformat="This is a very long line with a lot of stuff so they will take " 
    lineformat+="more than standard terminal width (80) columns... Progress %3d%%" 
    
    getWinSize() {
        {
            read twidth
            read theight
        } < <(
            tput -S - <<<$'cols\nlines'
        )
    }
    trap getWinSize WINCH
    getWinSize
    
    getCpos=$(tput u7)
    getCurPos() {
        stty raw -echo min 0
        echo -en "$getCpos"
        read -sdR CURPOS
        stty $oldstty
        IFS=\; read curv curh <<<"${CURPOS#$'\e['}"
    }
    oldstty=$(stty -g)
    
    before=$(tput -S - <<<$'ed\nsc')
    after=$(tput rc)
    n=0
    while [[ $n -ne 100 ]]; do
        n=$((n+1))
        printf -v outputstring "$lineformat" $n
        getCurPos
        uplines=$(((${#outputstring}/twidth)+curv-theight))
        if ((uplines>0)) ;then
            printf -v movedown "%${uplines}s" ''
            echo -en "${movedown// /\\n}"
            tput cuu $uplines
        fi
        printf "%s%s%s" "$before" "$outputstring" "$after"
        sleep .05
    done
    
    downlines=$((${#outputstring}/twidth))
    printf -v movedown "%${downlines}s" ''
    echo "${movedown// /$'\n'}"
    

提交回复
热议问题