Bash自动补全进阶:如何同时合并pwd与hostname命令输出及文件路径补全


阅读 2 次

理解Bash自动补全机制

Bash的自动补全功能通过complete内置命令和补全函数实现。典型的补全函数结构如下:

function _mycommand() {
    local cur prev
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    
    # 补全逻辑
    if [[ $COMP_CWORD -eq 1 ]]; then
        COMPREPLY=( $(compgen -W "arg1 arg2" -- "$cur") )
    fi
}
complete -F _mycommand mycommand

多命令输出合并补全

要实现同时补全pwdhostname的输出,我们可以这样修改补全函数:

function _command() {
    local cur
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    
    case $COMP_CWORD in
        1)
            # 合并pwd和hostname输出
            local pwd_output=$(pwd)
            local hostname_output=$(hostname)
            COMPREPLY=( $(compgen -W "$pwd_output $hostname_output" -- "$cur") )
            ;;
        *)
            # 其他位置的补全逻辑
            COMPREPLY=( $(compgen -f -- "$cur") )
            ;;
    esac
}
complete -F _command command

集成文件路径补全

要在补全中同时支持文件路径,可以使用compgen -f选项:

function _advanced_complete() {
    local cur
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    
    # 获取命令输出
    local cmd_outputs="$(pwd) $(hostname)"
    
    # 合并命令输出和文件补全
    COMPREPLY=( 
        $(compgen -W "$cmd_outputs" -- "$cur")
        $(compgen -f -- "$cur")
    )
    
    # 去重
    COMPREPLY=($(printf "%s\n" "${COMPREPLY[@]}" | sort -u))
}
complete -F _advanced_complete mycmd

实际应用示例

下面是一个更完整的示例,支持多级参数和不同类型的补全:

function _smart_complete() {
    local cur prev
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    
    case $prev in
        --path|-p)
            # 只补全目录
            COMPREPLY=( $(compgen -d -- "$cur") )
            ;;
        --host|-h)
            # 补全主机名相关
            COMPREPLY=( $(compgen -W "$(hostname) $(hostname -f) $(hostname -s)" -- "$cur") )
            ;;
        *)
            # 默认补全:命令选项+当前目录
            local options="--help --path --host"
            COMPREPLY=(
                $(compgen -W "$options" -- "$cur")
                $(compgen -f -- "$cur")
            )
            ;;
    esac
}
complete -F _smart_complete smartcmd

性能优化建议

当处理大量补全项时,可以考虑以下优化:

function _optimized_complete() {
    local cur
    cur="${COMP_WORDS[COMP_CWORD]}"
    
    # 使用数组而非字符串拼接
    local -a completions
    completions+=($(pwd))
    completions+=($(hostname))
    completions+=($(compgen -f -- "$cur"))
    
    # 使用关联数组去重
    local -A unique
    for item in "${completions[@]}"; do
        unique["$item"]=1
    done
    
    COMPREPLY=("${!unique[@]}")
}

错误处理与边界情况

完善的补全函数应该处理各种边界情况:

function _robust_complete() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    
    # 检查命令是否存在
    if ! command -v hostname &>/dev/null; then
        COMPREPLY=($(compgen -f -- "$cur"))
        return
    fi
    
    # 处理带空格的路径
    local pwd_output
    pwd_output=$(pwd | sed 's/ /\\ /g')
    
    # 安全合并输出
    COMPREPLY=()
    while IFS= read -r item; do
        COMPREPLY+=("$item")
    done < <(compgen -W "$pwd_output $(hostname)" -- "$cur" 2>/dev/null)
    
    # 添加文件补全
    mapfile -t files < <(compgen -f -- "$cur" 2>/dev/null)
    COMPREPLY+=("${files[@]}")
}