4

I need my bash script to get function names from user. The script should assist the users by auto completing the functions defined inside the same bash script file.

Eg:

myBash.sh

#!/usr/bash
function func1()
{
    echo "In func1 func"
}

function func2()
{
    echo "In func2 func"
}

function myFunc1()
{
    echo "In myFunc1 func"
}

while [ 1 ]
do
    echo -n "cmd>"
    read $userCmd
    $userCmd
done

]$ ./mybash.sh
cmd> my<tab><tab>
myFunc1

cmd> func<tab><tab>
func1 func2

This is my required output. How to accompany this?

3
  • Half an answer: use the -e option to read to use readline to process the input (which will include command completion). The harder half is to get readline to use only the locally defined functions as potential completions for a command name. Commented Jul 16, 2014 at 14:18
  • 1
    apparently it's real pain to do, and I don't know if the bug described in this answer has been corrected or not Commented Jul 16, 2014 at 14:54
  • @Ploutox - I was searching for that post, but couldn't remember how to find it. That bug bit me too when I tried to do this. Great find! Commented Jul 16, 2014 at 14:59

1 Answer 1

2

This workaround should do the trick.

    #!/bin/bash

    func1() {
        echo "You are in func1: $@"
    }
    
    func2() {
        echo "You are in func2: $@"
    }

    myFunc1() {
        echo "You are in myFunc1: $@"
    }
    
    # usage: autocomplete "word1 word2 ..."
    autocomplete() {
         # try to autocomplete the last word, and 
         # keep a record of the rest of the input
         OTHER_WORDS="${READLINE_LINE% *} " 
         if [[ ${#OTHER_WORDS} -ge ${#READLINE_LINE} ]]; then 
             # if there is only 1 word...
             OTHER_WORDS="" 
         fi
         
         # the -W flag tells compgen to read autocomplete
         # from the 1st argument provided, then we
         # evaluate the last word of the current line
         # through compgen
         AUTOCOMPLETE=($(compgen -W $1 "${READLINE_LINE##* }"))
         if [[ ${#AUTOCOMPLETE[@]} == 1 ]]; then 
             # if there is only 1 match, substitute it
             READLINE_LINE="$OTHER_WORDS${AUTOCOMPLETE[0]} "
             # position the cursor at the end of the word
             READLINE_POINT=${#READLINE_LINE}
         else
             #...otherwise print the possibilities
             echo -e "cmd> $READLINE_LINE\n${AUTOCOMPLETE[@]}" 
         fi
    }
    
    # list the values to be autocompleted
    MYFUNC="func1 func2 myFunc1" 
    # enable line editing
    set -o emacs
    # call autocomplete when TAB is pressed
    bind -x '"\t":"autocomplete \$MYFUNC"';   
    while read -ep "cmd> "; do
        # history is just a nice bonus
        history -s $REPLY
        eval ${REPLY}
    done

To try it :

    ]$ ./mybash.sh
    cmd> my<tab>
    cmd> myFunc1
    
    cmd> func<tab>
    func1 func2
    
    cmd> func1 hello, world!
    You are in func2: hello, world!

    cmd> func1 my<tab>
    cmd> func1 myFunc1

As mentioned in my previous comment, have a look at this question. It uses a nice trick to auto detect all inner functions in order to use it as auto-complete values.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.