具有用户定义函数的Bash脚本自动完成

3
我需要我的bash脚本从用户那里获取函数名称。该脚本应通过自动完成在同一bash脚本文件中定义的函数来帮助用户。
例如:
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

这是我需要的输出。如何陪伴它?

半个答案:使用-e选项来使用readline处理输入(其中将包括命令完成)。更难的部分是让readline仅使用本地定义的函数作为命令名称的潜在完成。 - chepner
1
显然这是一件很麻烦的事情,而且我不知道在这个答案中描述的错误是否已经被修复。 - Aserre
@Ploutox - 我在寻找那篇帖子,但是不记得如何找到它。当我尝试做这件事时,那个错误也困扰了我。太棒了,你找到了! - ghoti
1个回答

2
这个解决方法应该能解决问题。
    #!/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

试一下:

    ]$ ./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

如我先前的评论所提到的,您可以查看这个问题。它使用了一个巧妙的技巧来自动检测所有内部函数,以便将其用作自动完成值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接