4

Is it possible to format the STDERR in order to have a better looking menu using the select command?

I have a simple select

    select oChoice in $(<tempMenu.menu) ; do  
      case "$oChoice" in
          *) 
           break
          ;;
      esac
   done

I've tried a trick like:

    exec 3>&1
    select ...
    ...
    done 2>&1 1>&3 | sed 's/^/NICE OUTPUT    /'

But I cannot use escape sequences (i.e. colors), for example

   ...
   done 22>&1 1>&3 | sed 's/^/\033[1;33m\033[44mNICE OUTPUT    /'
   or
   done 22>&1 1>&3 | sed 's/^/\\033[1;33m\\033[44mNICE OUTPUT    /'

The escape sequences are not escaped and also the STDOUT is altered because I have customized the PS3 as well.

PS3="$(print \\n\\r)# $(print "\\033[1;33m\\033[44m")"$QUESTION"$(print "\\033[0m\\033[1;1m\\033[44m") `tput sc` $(print "")
#$(print "")
# $(print "")
# Status: $status $(print "")
# $(print "")
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  `tput rc` "

As far as I understand (Show only stderr on screen but write both stdout and stderr to file) I cannot separate the STDERR from the STDOUT, so, is there a smarter way to create dynamic text-based menus just using the STDOUT? (or an otherway to workaround my issue)

tmow
  • 1,255
  • 1
    consider editing your post to include the contents of tempMenu.menu. Hard to tell what your problem is without seeing what the inputs are. Good luck. – shellter May 18 '12 at 17:37
  • Thanks @shellter , I've found a solution using dialog instead of select. I'll update the question, or answer myself (not sure what is better to do) as soon as I'll have time to do it. – tmow May 22 '12 at 14:19

2 Answers2

1

Revisiting an old question to provide a less effort implementation. In fact, two questions in one:

a) Handling STDERR in a select command

b) Change the appearance of items shown in the select command

Alternate approaches have been addressed already -- i.e. meaning solutions that don't use the select command. So I will not walk this path.

The select command is quite handy in that it automatically handles the column layout of your options, and essentially all you have to do is the case handling. So rather then sort of reinventing the wheel it can be a good solution for many simple cases.

a) Handling of STDERR

You have already the solution in the original question: redirect STDERR to STDOUT.

select choice in ...; do
...
done 2>&1

Both file handles offer the same capabilities, so there is no reason, IMHO, to fiddle around with this. Using STDERR for select is actually a good idea as you do not clobber your STDOUT and can use it for other purposes, such as, for instance, redirection.

b) Change the appearance of items shown in the select command

The solution to enhance the output is pretty trivial here too if you adopt a syntax in the likes of:

select choice in $(...); do
...
done

Use $(...) to perform whatever make up of the select items.

Your could for instance, on an ANSI terminal, colourise them:

$(for i in *; do print "\[E31m$i\E[0m"; done)

or call a colourisation function (which becomes reusable in other circumstances):

function colourise_diritems {
    typeset dir=$1 item

    for item in $dir/*; do
        if [[ -d $item ]]; then print "\E[31m$i\E[0m"
        elif [[ -f $item ]]; then print "\E[32m$item\E[0m"
        ...
        fi
    done
}

select choice in $(colourise_diritems $PWD); do
   ...
done

Obviously if you add markup to the items, you'll have to clean up the result before using it; in the above example, before using the selected choice, you would have to do something like

choice=${choice#\E[+([^m]*)m}
choice=${choice%\E[+([^m]*)m}

to remove the ANSI sequences.

Note: playing around with ANSI sequences can be tricky and requires further testing.

  • Thanks! Yes this is right, I honestly forgot about this question and in the meanwhile I've replaced the menu based script with an option based one. Finally I prefer. Ah and I moved also to bash as we were using an old version of ksh that doesn't deal well with most of these nice stuff. – tmow Apr 14 '20 at 13:15
0

Another way is avoiding the select and make a menu. Make a shell script for each menu choice (action1.sh, xxx.sh and passwords.sh), configure them in menu.cfg:

1 action1 Do action 1
2 xxx Another nice item for you
3 passwords Very dangerous

And start a menu with a script that reads menu.cfg

#!/bin/ksh
formatmenu()
{
if [ $# -eq 2 ]
then
            printf "%d) %s\n" ${1} "$2" 
    else
            printf "    %s\n" "${1}"
    fi
}
showMenu()
{
    echo "Enter 0 to stop or choose beneath."
    cat menu.cfg|while read option proces description
    do
            formatmenu ${option} ${proces}
            formatmenu "${description}"
    done
}

getAction()
{
    showMenu
    while [ ${CHOICE} -eq -1 ]
    do
            read CHOICE?"Please enter a digit: "
            if [[ ${CHOICE} != +([0-9]) ]]
            then
                    CHOICE=-1
                    echo "Invalid, please enter a digit."
            fi
    done
}

performAction()
{
    if [ ${CHOICE} -eq 0 ]
    then
            return
    fi
    process=$(grep "^${CHOICE} " menu.cfg | cut -d\  -f2)


        echo "===${process}.sh==="
        . ${process}.sh
}

# Start

export CHOICE=-1
getAction
echo choice=${CHOICE} 
performAction
exit 0
Walter A
  • 736