A simple bash menu script

While refactoring code for maxperfwiz script I got sidetracked a bit and made this menu. It is probably going to be used in that script, but here it is if you want to use it or modify it for anything else. I'm still quite a newbie when it comes to bash scripting (I started to learn it somewhat seriously just a month or so ago), so any criticism that may lead to improvement is welcomed.

#!/bin/bash

function kresimenu() {
  # arguments: $1 - choices, separated by a delimiter
  #            $2 - delimiter
  #            $3 - message to print above the menu
  stty -echo
  tput smcup
  tput civis
  tput clear
  trap quit HUP TERM INT
  
  cols=$(tput cols)
  lines=$(tput cols)
  if (( $cols < 80 || $lines < 25 )); then 
    quit 1 "ERROR: Too small terminal window. Needs to be at least 80 by 25." 
    # TODO: implement scrolling if many choices
  fi

  IFS="$2" read -r -a options <<< "$1"
  
  echo -ne "$3" | fold -sw$cols
  echo -ne "\n\n"
  
  firstline=$(getCursorLine)
  n=${#options[@]}
  selected=0

  while true; do
    # print options:
    for ((i=0; i<n; i++)); do
      if [[ $selected == $i ]]; then
        tput rev
      else
        tput sgr0
      fi
      printf "\e[$((firstline+i));1H%-${cols}s" " ${options[i]}"
    done
    
    # wait for input
    read -rsn1 key
    [[ $key = $'' ]] && break
    [[ $key = $'\u1b' ]] && {
      read -rsn2 key
    }
    [[ -n $key ]] && {
      case "$key" in
        #'[D'|h )  ;;
        '[B'|j ) selected=$((selected >= n-1 ? n-1 : selected+1)) ;;
        '[A'|k ) selected=$((selected <= 0   ? 0   : selected-1)) ;;
        #'[C'|l )  ;;
        #q ) break ;;
        * ) continue ;;
      esac
    }
  done
  
  read -rt 0.001 && cat < /dev/stdin > /dev/null   #flush stdin, just in case
  stty echo  
  tput rmcup
  tput cnorm
  tput sgr0
  
  quit 0 ${options[selected]}
}

function getCursorLine() {
  IFS='[;' read -p $'\e[6n' -d R -a coords -rs || quit 2 "Error fetching coordinates."
  echo ${coords[1]}
}

quit() {
  # flush the stdin
  read -rt 0.001 && cat < /dev/stdin > /dev/null

  tput rmcup
  tput cnorm
  stty echo
  tput sgr0
  
  if [[ $1 = "0" ]]; then
    echo "$2"
  else 
    >&2 echo "$2"
  fi
  exit $1
}

kresimenu "alpha|beta|gamma|delta|epsilon" "|" "\033[1mKresimenu\033[0m by Krešimir\n\nTempus turpis potenti suscipit est bibendum habitant, feugiat tempor proin sociosqu at. In penatibus dis platea hendrerit himenaeos nam \033[1mullamcorper\033[0m consequat gravida, phasellus lacus quam laoreet erat pulvinar rhoncus metus, tincidunt accumsan taciti enim scelerisque dictum nunc varius. Curabitur magna iaculis integer eu class litora faucibus ante aenean facilisis mi rutrum habitasse inceptos cursus, malesuada imperdiet molestie ligula urna magnis commodo pellentesque diam porttitor eleifend volutpat natoque."
6 Likes

Forum kindly sponsored by