bash - How do I chain multiple user prompts together with the ability to go back a prompt? -


i wondering how can make bash script has multiple menus in it.

for example, here's user see upon running it:

type number of choosing: 1-play 2-load 3-exit 

1

what name: 

::prev::

type number of choosing: 1-play 2-load 3-exit 

1

what name: 

brad

where from, brad? 

pennsylvania

what favourite colour? 1-blue 2-red 3-green 4-grey 5-magenta 

,sdfhljalk:j;

what favourite colour? 1-blue 2-red 3-green 4-grey 5-magenta 

2

what favourite toy? 

train

what on sandwich? 

::prev::

what favourite toy? 

~`!@#$%^& * ()_+=-{}[]|\"':;?/>.<,

what favourite toy? 

::exit::

exiting.... 

i apologize being long, want cover bases new game i'm going making. want question end questions.

i want able type ::prev:: wherever , have go previous question, , i'd ::exit:: exit script wherever is. also, i'd unrecognized input during questions numbered responses reload question without continuing, , input containing characters may cause script break (something :;!@# ...) reload question instead of breaking.

any appreciated!

by way, i'm using os x yosemite

first thing in situation try , think of how, generally, implement this. biggest addition complexity using ::prev:: go question. means need represent application state in way such can move forward or backward.

luckily, pretty simple: it's implementation of stack need. visuals:

                                                                 ...           <--pop--             <--pop-- location prompt <--pop-- ...                    name prompt          name prompt              ... main menu --push-> main menu   --push-> main menu       --push-> ... 

this means each individual piece of program needs self-contained. can in shell scripting functions.

so need several pieces:

  • function displays menu , allows user choose value.
  • function displays text prompt , allows user choose value.
  • function manages stack represents state of program.
  • individual functions each piece of program.

let's first write our menu prompt function. part pretty easy. bash of work using select loop, prints menu us. we'll wrap can handle custom logic, expecting ::exit:: or ::prev:: , pretty-printing.

function show_menu {   echo "$1" # print prompt   ps3='> ' # set prompt string 3 '> '   select selection in "${menu_items[@]}" # print menu using menu_items array       if [[ "$reply" =~ ^(::exit::|::prev::)$ ]];       # if user types ::exit:: or ::prev::, exit select loop       # , return 1 function, $selection containing       # command user entered.       selection="$reply"       return 1     fi     # $selection blank if user did not choose valid menu item.     if [ -z "$selection" ];       # display error message if $selection blank       echo 'invalid input. please choose option menu.'     else       # otherwise, return success return code.       return 0     fi   done } 

we can use function so:

menu_items=('item 1' 'item 2' 'item 3') if ! show_menu 'please choose item menu below.';   echo "you entered command $selection." fi  echo "you chose $selection." 

great! on next item on agenda, writing code accepts text input user.

# prompt required text value. function prompt_req {   # do...while   while : ;     # print prompt on 1 line, '> ' on next.     echo "$1"     printf '> '     read -r selection # read user input $selection     if [ -z "$selection" ];       # show error if $selection empty.       echo 'a value required.'       continue     elif [[ "$selection" =~ ^(::exit::|::prev::)$ ]];       # return non-success return code if ::exit:: or ::prev:: entered.       return 1     elif [[ "$selection" =~ [^a-za-z0-9\'\ ] ]];       # make sure input contains whitelist of allowed characters.       # if has other characters, print error , retry.       echo "invalid characters in input. allowed characters a-z, a-z, 0-9, ', , spaces."       continue     fi     # break statement runs if no issues found input.     # exits while loop , function returns success return code.     break   done } 

great. function works first:

if ! prompt_req 'please enter value.';   echo "you entered command $selection." fi  echo "you entered '$selection'." 

now have user input handled, need handle program flow our stack-managing function. easy implement in bash using array.

when part of program runs , completes, ask flow manager run next function. flow manager push name of next function onto stack, or rather, add end of array, , run it. if ::prev:: entered, pop last function's name off of stack, or remove last element of array, , run function before it.

less talk, more code:

# program flow manager function run_funcs {   # define our "stack" initial value being function name   # passed directly run_funcs   funcs=("$1")   # do...while   while : ;     # reset next_func     next_func=''     # call last function name in funcs.     if "${funcs[${#funcs[@]}-1]}";       # if function returned 0, no :: command run user.       if [ -z "$next_func" ];         # if function didn't set next function run, exit program.         exit 0       else         # otherwise, add next function run funcs array. (push)         funcs+=("$next_func")       fi     else       # if function returned value other 0, command run.       # exact command run in $selection       if [ "$selection" == "::prev::" ];         if [ ${#funcs[@]} -lt 2 ];           # if there 1 function in funcs, can't go           # because there's no other function call.           echo 'there no previous screen return to.'         else           # remove last function funcs. (pop)           unset funcs[${#funcs[@]}-1]         fi       else         # if $selection isn't ::prev::, it's ::exit::         exit 0       fi     fi     # add line break between function calls keep output clean.     echo   done } 

our run_funcs function expects:

  • to called name of first function run, and
  • that each function runs output name of next function run next_func if execution of program must proceed.

alright. should pretty simple work with. let's write program now:

function main_menu {   menu_items=('play' 'load' 'exit')   if ! show_menu 'please choose menu below.';     return 1   fi    if [ "$selection" == 'exit' ];     exit 0   fi    if [ "$selection" == 'load' ];     # logic load game state     echo 'game loaded.'   fi    next_func='prompt_name' }  function prompt_name {   if ! prompt_req 'what name?';     return 1   fi   name="$selection"    next_func='prompt_location' }  function prompt_location {   if ! prompt_req "where from, $name?";     return 1   fi   location="$selection"    next_func='prompt_colour' }  function prompt_colour {   menu_items=('blue' 'red' 'green' 'grey' 'magenta')   if ! show_menu 'what favourite colour?';     return 1   fi   colour="$selection"    next_func='prompt_toy' }  function prompt_toy {   if ! prompt_req 'what favourite toy?';     return 1   fi   toy="$selection"    next_func='print_player_info' }  function print_player_info {   echo "your name $name."   echo "you $location."   echo "your favourite colour $colour."   echo "your favourite toy $toy."    # next_func not set, program exit after running function. }  echo 'my bash game' echo # start program, main_menu entry point. run_funcs main_menu 

everything in order now. let's try out our program!

$ ./bash_game.sh bash game  please choose menu below. 1) play 2) load 3) exit > ::prev:: there no previous screen return to.  please choose menu below. 1) play 2) load 3) exit > 2 game loaded.  name? > stephanie  from, stephanie? > ::prev::  name? > samantha  from, samantha? > dubl*n invalid characters in input. allowed characters a-z, a-z, 0-9, ', , spaces. from, samantha? > dublin  favourite colour? 1) blue 2) red 3) green 4) grey 5) magenta > aquamarine invalid input. please choose option menu. > 8 invalid input. please choose option menu. > 1  favourite toy? > teddie bear  name samantha. dublin. favourite colour blue. favourite toy teddie bear. 

and there have it.


Comments

Popular posts from this blog

node.js - Node js - Trying to send POST request, but it is not loading javascript content -

javascript - Replicate keyboard event with html button -

javascript - Web audio api 5.1 surround example not working in firefox -