3

I'm creating a bash script and I want to create a menu. When I run the code it displays the menu but the problem is when the user enters a choice it keeps re-printing the menu to ask again and again no matter what choice was selected.

#!/bin/bash

declare -i choice=1;

while ((choice!=5))
    do
    echo "Main Menu:"
    echo -e "\t(a) Add"
    echo -e "\t(b) Remove"
    echo -e "\t(c) Seach"
    echo -e "\t(d) Display"
    echo -e "\t(e) Exit"
    echo -n "Please enter your choice:"
    read choice
    case $choice in
           "a"|"A")
            echo "You entered a"
            ;;
            "b"|"B")
            echo "You entered b"
            ;;
            "c"|"C")
            echo "You entered c"
            ;;
            "d"|"D")
            echo "You entered d"
            ;;
            "e"|"E")
            echo "You entered e"
            ((choice=5))
            ;;
            *)
            echo "invalid answer"
            ;;

    esac
done
2
  • You can enable tracing in a shell script: replace the first line of the script by #!/bin/bash -x. You can enable and disable tracing by the command set -x and set +x, too. Information to the user should be written to standard error stream (stderr). This can be done by redirecting the echo output, e.g. echo "Main Menu:" >&2. Now it is possible to pipe the data output of your script to another command. If you really need a menu in a shell script than you can use the shell command select.
    – miracle173
    Mar 24, 2014 at 6:18
  • 1
    Please don't change the meaning of your question like that. If you have a new issue, post a new question instead.
    – terdon
    Mar 26, 2014 at 15:23

3 Answers 3

5

The first step whenever you are debugging something is to have your script print the various variables it is using. For example, here, if you add an echo $choice before the case statement, you will see that it will print 0 no matter what value you give it.

This is because you're using the -i option to declare which does (from help declare):

  -i    to make NAMEs have the `integer' attribute

So, you are declaring that variable to be an integer and then are passing it letters (strings) and since bash is expecting an integer, it converts it to a 0.

The next issue is that you are running a while loop that will only exit when $choice is 5. Even if the rest of your syntax were OK, that would only happen for choice e.

Here is a working example of your script. I have removed the declare which is unnecessary.

#!/bin/bash

## Use another variable to exit the loop
ok=0;

while ((ok==0))
    do
    echo "Main Menu:"
    echo -e "\t(a) Add a contact"
    echo -e "\t(b) Remove a contact"
    echo -e "\t(c) Seach contacts"
    echo -e "\t(d) Display contacts"
    echo -e "\t(e) Exit"
    echo -n "Please enter your choice:"
    read choice
    case $choice in
        "a"|"A")
        ok=1
            ;;
        "b"|"B")
        ok=1
            ;;
        "c"|"C")
        ok=1
            ;;
        "d"|"D")
            ok=1
        ;;
        "e"|"E")
            exit
        ;;
            *)
            echo "invalid answer, please try again"
            ;;

    esac
done

echo "You entered $choice"
1
  • Thanks for your help, i updated my code above and I'm having some difficulties on how to remove and search a contacts when it is formatted on multiple lines. Mar 26, 2014 at 15:13
0

You can do it using build-in function select:

echo "Main Menu:"
echo -e "\t(a) Add a contact"
echo -e "\t(b) Remove a contact"
echo -e "\t(c) Seach contacts"
echo -e "\t(d) Display contacts"
echo -e "\t(e) Exit"
echo "Please enter your choice:"

choices=("a" "b" "c" "d" "e" "Quit")
select choice in "${choices[@]}"
do
    case $choice in
        "a")
            echo "you chose choice a"
            ;;
        "b")
            echo "you chose choice b"
            ;;
        "c")
            echo "you chose choice c"
            ;;
        "d")
            echo "you chose choice d"
            ;;
        "e")
            echo "you chose choice e"
            ;;
        "Quit")
            break
            ;;
        *) echo invalid option;;
    esac
done

It is easier to use, and you can read your choices from file. Also if want to exit from menu for any choice, just add break after each choice.

0

Open the terminal and type:

sudo apt-get install 9menu  

9menu creates X menus from the shell. This is a simple program that allows you to create X menus from the shell, where each menu item will run a command.

Run the following command to create your menu:

9menu -label "Main Menu" 'Add:echo "You entered a"' 'Remove:echo "You entered b"' 'Search:echo "You entered c"' 'Display:echo "You entered d"' 'Exit:echo "You entered e"'

It's all done by this one-line command, and because 9menu displays the menu graphically, there is no need to add an "invalid answer" error condition, because the menu entries are selected from the Main Menu window with a mouse click, and there are only five possible entries in the menu that can be selected by clicking them with the mouse.

I suggest that you make the following improvement to your original menu idea. Instead of displaying "You entered e" when you click Exit, why not use the exit menu item to close the Main Menu window and exit from 9menu? To do it that way use the following command:

9menu -label "Main Menu" 'Add:echo "You entered a"' 'Remove:echo "You entered b"' 'Search:echo "You entered c"' 'Display:echo "You entered d"' exit  
7
  • 2
    maybe this is be a useful comment but it does not explain why the script does not work.
    – miracle173
    Mar 24, 2014 at 6:23
  • @miracle173 Both of the scripts work. The first script is written to the specifications stated in the question. The second script has an improvement over the original design stated in the question, which gives it more user-friendly exit condition. You claim that the script does not work. Did you first run sudo apt-get install 9menu before running the script? Remember, this is a shell script, so the terminal program that is required must first be installed.
    – karel
    Mar 24, 2014 at 6:37
  • 3
    your answer does not explain why the script of the OP does not work
    – miracle173
    Mar 24, 2014 at 7:19
  • @miracle173 You're a mathematician with rep as one, so I'm trying to give this to you completely logically without appearing to be condescending in any way. The bash code in the question is 37 lines of poorly constructed code. The bash code in my answer is 1 line of correctly constructed bash code. My explanation to a mathematician is that my code is designed to be concise, to be accurate and to formulate the assignment correctly without any need for any additional proofs by counterexample. I'm asking you to be charitable and consider it from my point of view.
    – karel
    Mar 24, 2014 at 7:37
  • 2
    I have to say I agree with @miracle173. Your code just introduces a needless dependency for what is an extremely simple task and you assume that GUI is better while you have no knowledge of what the script will be for. This was a bash question and you bring in an X program which immediately makes it harder to install, less portable and heavier. It also does not answer the actual question which was "what's wrong with my script"? While this might be a useful tool, you don't explain how this can be integrated into the script, how will the OP capture the user's choice and process it in her script?
    – terdon
    Mar 26, 2014 at 15:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .