【问题标题】:Bash complete function - Separating completion parts with character other than spaceBash 完成功能 - 用空格以外的字符分隔完成部分
【发布时间】:2020-07-15 21:19:24
【问题描述】:

我编写了一个 bash 补全脚本来完成文件/目录补全,但使用 . 作为分隔符而不是 /。但是,它的行为不像我预期的那样。

在我进一步深入之前,有没有人知道这方面的任何选择,或者已经写好的可以做到这一点的东西?这样做的动机是在使用 -m 标志调用 python 时启用完成。这似乎很疯狂,这还不存在,但我找不到任何相关的东西。

我的问题是 bash 无法将 . 识别为完成选项的分隔符,并且在我在当前命令的末尾添加一个额外的空格之前不会显示下一个选项。

这里有几个具体的例子,给定这个目录结构。

/module
    /script1.py
    /script2.py

例如,当我使用ls 命令时,它的工作原理是这样的

$ ls mo<TAB>
$ ls module/<TAB><TAB>
   script1.py    script2.py

但是,使用我的函数,它的工作方式如下:

$ python -m mod<TAB>
$ python -m module.<TAB><TAB>
   module.

因此,它不再显示下一个条目,而是再次显示完成的字符串。但是,如果我添加一个空格,它就会起作用,但我不希望它包含空格:

$ python -m mod<TAB>
$ python -m module. <TAB><TAB>  # (note the space here after the dot)
   script1    script2           # (Note, I'm intentionally removing the file extension here).

我希望补全功能与底部示例一样,但不强制包含转到下一组选项的空间

我打开了大约 50 个标签,并尝试了很多建议,但似乎没有什么能够按照我的意愿解决这个问题。这里还有一些其他警告需要花费大量时间才能完成,所以如果我跳过了一些重要的内容,我很乐意扩展任何其他点。我在下面附上了我的代码,任何帮助将不胜感激。谢谢!

#!/bin/bash

_python_target() {
    local cur opts cur_path
    # Retrieving the current typed argument
    cur="${COMP_WORDS[COMP_CWORD]}"

    # Preparing an array to store available list for completions
    # COMREPLY will be checked to suggest the list
    COMPREPLY=()

    # Here, we'll only handle the case of "-m"
    # Hence, the classic autocompletion is disabled
    # (ie COMREPLY stays an empty array)
    if [[ "${COMP_WORDS[1]}" != "-m" ]]
    then
        return 0
    fi

    # add each path component to the current path to check for additional files
    cur_path=""
    for word in ${COMP_WORDS[@]:2:COMP_CWORD-2}; do
        path_component=$(echo ${word} | sed 's/\./\//g')
        cur_path="${cur_path}${path_component}"
    done
    cur_path="./${cur_path}"

    if [[ ! -f "$cur_path" && ! -d "$cur_path" ]]; then
        return 0
    fi

    # this is not very pretty, but it works. Open to comments on this too
    file_opts="$(find ${cur_path} -name "*.py" -type f -maxdepth 1 -print0 | xargs -0 basename -a | sed 's/\.[^.]*$//')"
    dir_opts="$(find ${cur_path} ! -path ${cur_path} -type d -maxdepth 1 -print0 | xargs -0 basename -a | xargs -I {} echo {}.)"

    opts="${file_opts} ${dir_opts}"

    # We store the whole list by invoking "compgen" and filling
    # COMREPLY with its output content.
    COMPREPLY=($(compgen -W "$opts" -- "$cur"))
    [[ $COMPREPLY == *\. ]] && compopt -o nospace

}

complete -F _python_target python

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    这是一个草稿示例:

    _python_target()
    {
        local cmd=$1 cur=$2 pre=$3
    
        if [[ $pre != -m ]]; then
            return
        fi
    
        local cur_slash=${cur//./\/}
        local i arr arr2
    
        arr=( $( compgen -f "$cur_slash" ) )
        arr2=()
        for i in "${arr[@]}"; do
            if [[ -d $i ]]; then
                arr2+=( "$i/" )
            elif [[ $i == *.py ]]; then
                arr2+=( "${i%.py}" )
            fi
        done
        arr2=( "${arr2[@]//\//.}" )
    
        COMPREPLY=( $( compgen -W "${arr2[*]}" -- "$cur" ) )
    }
    
    complete -o nospace -F _python_target python
    

    用python-2.7.18源码目录试试:

    【讨论】:

    • 对不起,我花了这么长时间才接受,这很好用,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 2017-09-23
    相关资源
    最近更新 更多