Bash Prompt #4: Disk Free Widget, Take 2

Bash Prompt Index

I've reworked the code from Bash Prompt #3: Disk Free Widget. The name is now dfsl. It's much longer, but also more flexible and has a help function (accessed by dfsl -h). This is a little odd given this isn't meant to be run at the command line, but as it has no man page a help function makes it easier to understand without having to read the code. It would be included in the prompt like this:

$ export PS1="\$(dfsl) \u@\h:\w\$ "
○◐○● giles@sli7-f:/home/giles/tmp$

This appears the same as the function shown previously, but you can now choose to not use colours (use -n). Other options are shown by the help:

$ dfsl -h
    dfsl [-h] [-b] [-p] [-t]
    'df' Stop Light
    Show characters for disk-free for each mount point on the system.
    -h            Help: show this help and exit
    -n            No Colour: use no colour codes at all
    -b            Bash: (default) display for Bash command line
    -p            Prompt: use Bash colours (unless '-n'), but no trailing return
    -t            Tmux: use tmux colours (unless '-n')
    -o <value>    Okay: df percentages below <value> are considered okay
    -w <value>    Warning: df percentages above <value> are shown as warnings
Thresholds are 70% and 90% (user-configurable in the code).
Disk indicators with and without colour:
○ ○ - below 70% full
◐ ◐ - between 70% and 90% full
● ● - above 90% full

dfsl can also be embedded in the tmux status line with set -g status-right '#(dfsl -t)... - -t will cause it to use tmux colours, or if you prefer no colours, add -n as well.

Here's the full code. Most of the added material is basic logic, the core of the functionality was explained in the post disk free TUI script: please see that first for an explanation.

#!/bin/bash
# filename: dfsl
#
# "'df' StopLight"
# Show one character for each mount point on the machine.  Each character
# is coloured and styled to indicate relative 'df' status.
#
# Output is available (via command line switches) for command line
# (default), prompt (no trailing newline) and tmux (different colour
# codes).  Can be had with or without colours.
#
# WARNING: guaranteed to not work on a Mac.

###############################################################################
#                            User-adjustable settings:
###############################################################################

# Adjust these numbers to reflect when you want to be warned.
okay=70     # percentage
warning=90

# You can use any character you want below.  They're probably
# font-dependent.  I use ':digraphs' in Vim to find specialty characters
# like these (if you don't know what that means, don't worry about it).
warning_char="●"
mid_char="◐"
okay_char="○"

# Bash Colours (don't change these):
b_green='\001\033[38;5;010m\002'
b_yellow='\001\033[38;5;011m\002'
b_red='\001\033[38;5;009m\002'
b_nocolour='\001\033[0;0m\002'

# Change these:
b_okay="${b_green}"
b_mid="${b_yellow}"
b_warning="${b_red}"

# tmux Colours (don't change these):
t_green='#[fg=green]'
t_yellow='#[fg=yellow]'
t_red='#[fg=red]'
t_nocolour=''

# Change these:
t_okay="${t_green}"
t_mid="${t_yellow}"
t_warning="${t_red}"

###############################################################################
#                         End User-adjustable settings
###############################################################################

myhelp () {
    cat << EOF
    $(basename "${0}") [-h] [-b] [-p] [-t]
    'df' Stop Light
    Show characters for disk-free for each mount point on the system.
    -h            Help: show this help and exit
    -n            No Colour: use no colour codes at all
    -b            Bash: (default) display for Bash command line
    -p            Prompt: use Bash colours (unless '-n'), but no trailing return
    -t            Tmux: use tmux colours (unless '-n')
    -o <value>    Okay: df percentages below <value> are considered okay
    -w <value>    Warning: df percentages above <value> are shown as warnings
Thresholds are ${okay}% and ${warning}% (user-configurable in the code).
Disk indicators with and without colour:
EOF
echo -e "${b_okay}${okay_char}${b_nocolour} ${okay_char} - below ${okay}% full"
echo -e "${b_mid}${mid_char}${b_nocolour} ${mid_char} - between ${okay}% and ${warning}% full"
echo -e "${b_warning}${warning_char}${b_nocolour} ${warning_char} - above ${warning}% full"
}

stoplight () {
    while read -r mountpoint
    do
        percent=$( df --output=pcent "${mountpoint}" | tail -n +2 | tr -d '%' )
        # shellcheck disable=SC2086  # "quote to prevent globbing/splitting"
        if [ ${percent} -gt ${warning} ]
        then
            t_colour="${t_warning}"
            b_colour="${b_warning}"
            df_stoplight_char="${warning_char}"
        elif [ ${percent} -gt ${okay} ]
        then
            t_colour="${t_mid}"
            b_colour="${b_mid}"
            df_stoplight_char="${mid_char}"
        else
            t_colour="${t_okay}"
            b_colour="${b_okay}"
            df_stoplight_char="${okay_char}"
        fi
        if ${tmux}
        then
            echo -en "${t_colour}${df_stoplight_char}${t_nocolour}"
        else
            echo -en "${b_colour}${df_stoplight_char}${b_nocolour}"
        fi
    done < <( lsblk --output MOUNTPOINT --noheadings | grep -v '^$' | grep -v '[SWAP]' ; mount | grep " cifs " | awk '{ print $3 }' )
    if ! ${prompt}
    then
        echo
    fi
}

dieifnotpercent () {
    # Obviously it would be better if these two "if" statements were
    # combined: I'm not sure if it was my logic or Bash's that was failing
    # (more likely mine!) but I couldn't combine them successfully.
    if ! [[ ${1} =~ ^[0-9]+$ ]]
    then
        myhelp
        echo "*** Values for 'okay' and 'warning' must be between 0 and 100."
        exit 1
    fi
    if ! (( ${1} >= 0 && ${1} <= 100 ))
    then
        myhelp
        echo "*** Values for 'okay' and 'warning' must be between 0 and 100."
        exit 1
    fi
}

bash="false"
colour="true"
prompt="false"
tmux="false"
# shellcheck disable=SC2034 # "'bash' appears unused" ... correct ...
while getopts :bhnpto:w: opt ; do
    case $opt in
        b)  bash="true" ;;
        h)  myhelp ; exit 0 ;;
        n)  colour="false"
            b_okay=""
            b_mid=""
            b_warning=""
            b_nocolour=""
            t_okay=""
            t_mid=""
            t_warning=""
            ;;
        o)
            dieifnotpercent "${OPTARG}"
            okay=${OPTARG}
            ;;
        p)  prompt="true"; bash="true" ;;
        t)  tmux="true" ;;
        w)
            dieifnotpercent "${OPTARG}"
            warning=${OPTARG}
            ;;
        \?)
            echo "invalid option: -${OPTARG}" >&2
            help
            exit 1
            ;;
        :)
            echo "option -${OPTARG} requires an argument." >&2
            help
            exit 1
            ;;
    esac
done

stoplight