Bash to Ash, errors and adjustments

I wrote Bash script and now I want to convert it to Ash. One headache is this function:

do_adduser() {
    setaddprompt
    _arr_add=("Add manually" "Add via TXT" "return to main menu" "exit program")
    select add_action in "${_arr_add[@]}"
    do
        case "$REPLY" in
            1) do_manual_add ;;
            2) do_txt_add ;;
            3) return ;;
            4) exit 0 ;;
            *) badchoice ;;
        esac
        setaddprompt
    done
}

This function prints out the options and allows selection. First the ash error handler had me change the brackets as such

   _arr_add={"Add manually" "Add via TXT" "return to main menu" "exit program"}
    select add_action in "$(_arr_add[@])"

Which I think will be better. But now it is complaining about a missing "}" bracket.

line 72: syntax error: unexpected "do" (expecting "}")

When I get rid of the do statement, the error goes away. I tried adding a while before hand. It didn't make a difference so it's presently uncommented, and the code is bellow.

do_adduser() {                                                         
    setaddprompt                                                       
   # _arr_add={"Add manually" "Add via TXT" "return to main menu" "exit program"}
    #select add_action in "$(_arr_add[@])"                                       
    echo "Select Option:                                                         
1) Add manually                                                                  
2) Add via TXT                                                                   
3) Return to Main Menu                                                           
4) Exit Program                                                                  
"                                                                                
   # while[true];                                                                
     do;                                                                         
                                                                                 
        case "$REPLY" in                                                         
            1) do_manual_add ;;                                                  
            2) do_txt_add ;;                                                     
            3) return ;;                                                         
            4) exit 0 ;;                                                         
            *) badchoice ;;                                                      
        esac                                                                     
        setaddprompt                                                             
     done                                                                        
}                     

Does anybody know how I can change this to an 'ash' script successfully?

---------- Post updated at 06:17 PM ---------- Previous update was at 06:14 PM ----------

To summarize, I can't get the 'do' statement to work.

In what way does it "not work"?

Thanks in helping me out.

The do statement needs the following syntax:

while ...
do ...
done ...

I didn't have a "while" section to it when I was using Bash, and the command prompt just waited for me to enter a key. Now that I require the while statement, I don't know how to replicate that behavior.

I could do

while read ...
do..
done..

But then the user needs to press enter to continue. That's not as nice.

Which ash? busybox? I don't think either allow arrays or implements select ...; do...; done . You'll have to implement your own menu altogether.

#!/bin/busybox sh
while :; do
        setaddprompt

        printf '%d.) %s\n' 1 "Add manually" 2 "Add via TXT" 3 "return to main menu" 4 "exit program"
        read var
        case $var in
                1) do_manual_add; ;;
                2) do_txt_add; ;;
                3) break; ;;
                4) exit 0; ;;
                *) badchoice; ;;
        esac

        setaddprompt
done
1 Like

Thank you Scott, your code worked without any modification. I'm still new to scripting.

How do you make it so that, for the case statement, the user doesn't have to press 'enter'. I want it to be as soon as they press "1", for example, they're taken to that menu.

Tricky details..

The version of ash I have appears to support -n:

$ busybox ash
# IFS="" read -r -n 1 REPLY
q
# echo $REPLY
q
#

It returns immediately after 1 byte is read.

You could also do lots of tricky things with dd and stty, which might work more reliably. From this thread:

inkey() { char="" ; stty -icanon min 0 time 1 ; char=`dd count=1 if=/dev/tty 2>/dev/null` ; }

The reason this is more reliable is, if someone hits F1 and dumps \x1b[11~ into your terminal, that'd be one keystroke with inkey() and five keystrokes with read -n.

Also, inkey times out eventually, leaving "char" blank if nothing was typed. The timeout is in tenths of a second, for 1 second it'd be "time 10" for example.

If you gave it an infinite timeout, it might start waiting for entire lines again, terminals are tricky like that.

It works in ash for me, though it mostly depends on whether whatever embedded thing you're using has stty.

Thank you! It worked like a charm.