tags:

views:

318

answers:

3

Hi folks.

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.

A: 

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.
dz
works great! thank you so much.
Chasester
+1  A: 

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 ...
Dennis Williamson
thank you, lemme give it a shot. I was just prettying it up
Chasester
+1 for this nice trick. I though also embedding the lines in the "in" satement, but like in the for builtin you get into trouble with whitepsaces. But changing IFS does the trick.
dz
seems to work good Dennis. I just removed the line = part.One Q though - how could I have it return to the menu after the menu item has been displayed?
Chasester
Found it! "") echo Hit Enter to see menu again! continue ;;
Chasester
+1  A: 

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
Dennis Williamson
Thank you Dennis. I can't access it while not at work. but I'll give it a whirl when I get back there. Thank you so much.
Chasester