2

I created the world's ugliest menu using the first Linux tool I'm learning, BASH.

What the Menu Looks Like

The following /usr/local/bin/bell/sounds were found
1) /usr/local/bin/bell/sounds/Amsterdam.ogg
2) /usr/local/bin/bell/sounds/bell.ogg
3) /usr/local/bin/bell/sounds/Blip.ogg
4) /usr/local/bin/bell/sounds/default.ogg
5) /usr/local/bin/bell/sounds/Mallet.ogg
6) /usr/local/bin/bell/sounds/message.ogg
7) /usr/local/bin/bell/sounds/Positive.ogg
8) /usr/local/bin/bell/sounds/Rhodes.ogg
9) /usr/local/bin/bell/sounds/Slick.ogg
'a' to hear to all files, use number to hear a single file, 
'u' to update last single file heard as new default, or 'q' to quit:

The Code

#! /bin/bash

# NAME: bell-select-menu
# PATH: /usr/local/bin
# DESC: Present menu of bell sounds to listen to all, listen to one and update default.
# CALL: bell-select-menu
# DATE: Created Oct 1, 2016.

echo "The following /usr/local/bin/bell/sounds were found"

# set the prompt used by select, replacing "#?"
PS3="'a' to hear to all files, use number to hear a single file, 
'u' to update last single file heard as new default, or 'q' to quit: "

lastfile="none"

# allow the user to choose a file
select filename in /usr/local/bin/bell/sounds/*.ogg

do

    # leave the loop if the user types 'q'
    if [[ "$REPLY" == q ]]; then break; fi

    # play all if the user types 'a'
    if [[ "$REPLY" == a ]] 
    then 
        playall-bells
        continue
    fi

    # update last file name as new default if the user types 'u'
    if [[ "$REPLY" == u ]]
    then
        if [[ "$lastfile" == none ]]
        then
            echo "No file was selected."
            break
        fi
        echo "$lastfile selected"
        cp $lastfile /usr/local/bin/bell/sounds/default.ogg
        load-default-bell
        break
    fi

    # complain if no file was selected, and loop to ask again
    if [[ "$filename" == "" ]]
    then
        echo "'$REPLY' is not a valid number"
        continue
    else
        lastfile="$filename"
    fi

    # listen to the selected file
    ogg123 "$filename"

    # loop back to ask for another
    continue
done

I based the code on an answer from AskUbuntu: Create bash menu based on file list (map files to numbers). The menu scrolls off the screen as user options are repeatedly entered though, so the loop needs to be adjusted.

The world's ugliest menu is automatically generated so I can't hard code ASCII line draw characters on the left and right sides. Would I need to call a program to reformat the menu?

The bulk of the menu is generated by a single bash command:

select filename in /usr/local/bin/bell/sounds/*.ogg

I read the Bash manual on the select statement but don't see any options. Is there a program that can be called to massage the screen?

The closest thing I've found is called tput described here: linuxcommand.org/lc3_adv_tput but I'm not sure if it's practical for this problem.

Thanks in advance :)

PS This menu is one of the tools to get rid of annoying loud speaker beep in Terminal and gedit as described here: Turn off Motherboard/PC Speaker "beep" in Ubuntu 16.04 regression


Edit - Incorporating Accepted Answer

Many thanks to wjandrea for posting code to clean up the menu. Prior to the accepted answer I had added code for color in echo strings and PS3 (prompt). I had also put in a loop to redraw the menu to prevent it scrolling off the screen. I also put in a reset to clear the screen before repainting. This prevents more and old copy (sometimes truncated) and new copy of the menu appearing at the same time.

New Menu Look

The colors aren't accurately represented when copying from terminal text output and pasting into AskUbuntu.

=====  Sound Files for Bell in /usr/local/bin/bell/sounds/  ====

1) Amsterdam.ogg  4) default.ogg    7) Positive.ogg
2) bell.ogg       5) Mallet.ogg     8) Rhodes.ogg
3) Blip.ogg       6) message.ogg    9) Slick.ogg

===========================  Options  ==========================

'a' to hear to all files, use number to hear a single file, 
'u' update last number heard as new bell default, 'q' to quit: 

This is all that appears on the screen now. There is no $ sudo bell-menu call statement visible. No other history of previous commands typed visible.

A screen shot shows the colors accurately and you can see the screen has been programmatically blanked out:

bell-menu

New Menu Code

#! /bin/bash

# NAME: bell-menu
# PATH: /usr/local/bin
# DESC: Present menu of bell sounds to listen to all, listen to one and update default.
# CALL: sudo bell-menu
# DATE: Created Oct 6, 2016.

# set the prompt used by select, replacing "#?"
PS3="
===========================  Options  ==========================

$(tput setaf 2)'$(tput setaf 7)a$(tput setaf 2)' to hear to all files, use $(tput setaf 7)number$(tput setaf 2) to hear a single file, 
'$(tput setaf 7)u$(tput setaf 2)' update last number heard as new bell default, '$(tput setaf 7)q$(tput setaf 2)' to quit: $(tput setaf 7)"

cd /usr/local/bin/bell/sounds/

# Prepare variables for loops
lastfile="none"
wend="n"

while true; do

  tput reset # Clear screen so multiple menu calls can't be seen.

  echo
  echo -e "===== \e[46m Sound Files for Bell in /usr/local/bin/bell/sounds/ \e[0m ===="
  echo

  # allow the user to choose a file
  select soundfile in *.ogg; do

    case "$REPLY" in
        q) # leave the loop if the user types 'q'
            wend="y" # end while loop
            break    # end do loop
            ;;
        a) # play all if the user types 'a'
            playall-bells
            break    # end do loop
            ;;
        u) # update last file name as new default if the user types 'u'
            if [[ "$lastfile" == none ]]; then
                echo "No file has been heard to update default. Listen first!"
                continue  # do loop repeat
            fi
            echo "$lastfile selected"
            cp "$lastfile" default.ogg
            load-default-bell
            wend="y" # end while loop
            break    # end do loop
            ;;
    esac

    # complain if no file was selected, and loop to ask again
    if [[ "$soundfile" == "" ]]; then
        echo "$REPLY: not a valid selection."
        continue    # repeat do loop
    else
        lastfile="$soundfile"
    fi

    # listen to the selected file
    canberra-gtk-play --file="$soundfile"

    # loop back to ask for another
    break
  done
  if [[ "$wend" == "y" ]]; then break; fi

done

The menu was renamed from bell-select-menu to bell-menu. Because it resides in /usr/local/bin it needs to be called with sudo bell-menu and the comments were updated to reflect this fact.

With a little work the world's ugliest menu and now become and acceptable looking (but not beautiful) menu.

  • What's the goal here? Do you want to add colours and a border, or just make it easier to read? If it's the latter, you could list the basenames of the files instead of listing their full paths. – wjandrea Oct 4 '16 at 1:34
  • I didn't list the full paths, it's built into the bash command isn't it? But yes the overall goal is to make it eye-pleasing / user-friendly. – WinEunuuchs2Unix Oct 4 '16 at 1:37
  • If I change directory to /usr/local/bin/bell/sounds/ before calling bell-select-menu the select filename bash command still puts in the directory prefix. It would be nice to take it out directory prefix and insert spaces in front of menu numbers. – WinEunuuchs2Unix Oct 4 '16 at 1:46
2

Here's how I would do it. The most important thing I changed is that the script moves to the directory before listing the files, and it lists them as their relative path instead of their absolute path.

Also, I made $PS3 much smaller; used canberra-gtk-play because it's preinstalled, where ogg123 isn't; and used a case statement instead of multiple if statements.

I couldn't test it because I'm running 14.04.

#! /bin/bash

# NAME: bell-select-menu
# PATH: /usr/local/bin
# DESC: Present menu of bell sounds to listen to all, listen to one and update default.
# CALL: bell-select-menu
# DATE: Created Oct 1, 2016.

# set the prompt used by `select`, replacing "#?"
PS3=": "

echo "Options:
a) Play all 
u) Set the last file played as the new default
q) Quit
The following sounds were found in /usr/local/bin/bell/sounds/:"

cd /usr/local/bin/bell/sounds/

# Prepare var for the loop.
lastfile="none"

# allow the user to choose a file
select soundfile in *.ogg; do

    case "$REPLY" in
        q) # leave the loop if the user types 'q'
            break
            ;;
        a) # play all if the user types 'a'
            playall-bells
            continue
            ;;
        u) # update last file name as new default if the user types 'u'
            if [[ "$lastfile" == none ]]; then
                echo "No file was selected."
                break
            fi
            echo "$lastfile selected"
            cp "$lastfile" default.ogg
            load-default-bell
            break
            ;;
    esac

    # complain if no file was selected, and loop to ask again
    if [[ "$soundfile" == "" ]]; then
        echo "$REPLY: not a valid selection."
        continue
    else
        lastfile="$soundfile"
    fi

    # listen to the selected file
    canberra-gtk-play --file="$soundfile"

    # loop back to ask for another
    continue
done
| improve this answer | |
  • Works great! I'm going to add a little color. I like the fact canberra-gtk-play doesn't scroll the screen like ogg123 does. I was wrong thinking ogg123 was a built in command, I guess I forgot installing it somewhere along the line. I need to update my other scripts to use canbera as well. – WinEunuuchs2Unix Oct 5 '16 at 23:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.