Bash Menu: Return to menu after selection made and

2019-08-27 16:50发布

问题:

I've got a bash script that writes to a file. at the end of the script I want to display a menu, with line numbers - and have the user be able to select 1 or 2, (etc. up to the number of lines in the file) then have it execute that line.

Up to here is perfect.

However, after the line is executed (say for example it displays another file.) I'd like to return to the menu and let the user select another number. Including zero for exiting the menu.

Once the menu is displayed I have the following. (dumpline being the line of the file read)

     dresult=`sed -n "$dumpline"p "$PWD"/"$myday1"_"$myjob".txt`
     $dresult

But right now - after running the variable $dresult - it exits the shell (where instead I'd like the menu displayed.

Any thoughts?

thank you in advance.

回答1:

I think, you need something like a loop. Here is a small skelleton for executing a selected line from file:

#!/bin/bash

dumpfile="bla.txt"

echo "ls
echo 'hello'" > ${dumpfile}

function do_action {
    line="$( sed -n "${1},1p" "$dumpfile" )"
    (
        eval "${line}"
    )
}

cat -n $dumpfile
nr=$( cat "${dumpfile}" | wc -l )
PS3="select line nr or nr for QUIT: "
select ACTION in $( seq "$nr" ) QUIT
do
    case $ACTION in
        QUIT) echo "exit" ; break ;; #EXIT
        *) do_action "$ACTION" ;;
    esac
done

But be aware of the following:

  • Using eval might be not allways be a good idea (escaping is hard). Sometimes $line should be sufficient.
  • Using a subshell prevents changing variables by executing a line of the file. It also does prevent exiting the script from lines that do normally exits a shell.


回答2:

Here's another way to do a menu which relies on cat having the ability to number the lines of a file (some versions of cat may not have that - see the second example if this is the case). Both examples are for a simple four-item menu:

while [[ 1 ]]
do
    cat -n menufile
    read -p "Make a selection " choice
    case $choice in 
        1|2) 
           echo "A or B"
           ;;
        3) 
           echo "C"
           ;;
        4) 
           break
           ;;
        *) 
           echo "Invalid choice"
           ;;
    esac
done

This doesn't require cat -n:

saveIFS="$IFS"
IFS=$'\n'
read -d '' -a menuarray < menufile
IFS="$saveIFS"

for (( i=0; i<${#menuarray[@]}; i++ ))
do
    menu=$menu"$(($i+1))) ${menuarray[i]}"$'\n'
done

while [[ 1 ]]
do
    echo "$menu"
    read -p "Make a selection " choice
    case $choice in 
        1|2) 
           echo "A or B"
           ;;
        3) 
           echo "C"
           ;;
        4) 
           break
           ;;
        *) 
           echo "Invalid choice"
           ;;
    esac
done


回答3:

My comments on dz's answer are too long for a comment, so I'm posting them here:

Using seq with select would make a redundant-looking menu, with no correlation between it and the display of the lines in $dumpfile:

ls
echo 'hello'

1) 1
2) 2
etc.

You could do something like this instead:

saveIFS=$IFS
IFS=$'\n'
menu=$(< $dumpfile)
PS3="Make a selection: "
select ACTION in $menu QUIT
do
    IFS=$saveIFS
    case ...


标签: bash menu sed