有没有办法在当前会话中自定义“可编程完成”?

有没有办法在当前会话中自定义“可编程完成”?

如果我开始输入命令或文件名,我可以使用 Tab 键自动完成我的字符串。有没有办法改变当前 bash 会话的自动完成行为?

例如

Tab Tab在当前会话中按下时,*.txt只会显示包含的文件。

自动完成功能如何工作?是否有一组环境变量或可以调整的东西来改变自动完成行为?

答案1

在该bash_completion机制中,bash 函数_filedir_xspec()负责文件名和目录名的补全。这个函数可以在脚本中找到/etc/bash_completion

您可以编辑该函数并添加包含正则表达式的行。例如使用这个函数(它是原始函数的副本):

_filedir_xspec()
{
    local IFS cur xspec

    IFS=$'\n'
    COMPREPLY=()
    _get_comp_words_by_ref cur

    _expand || return 0

    # get first exclusion compspec that matches this command
    xspec=$( awk "/^complete[ \t]+.*[ \t]${1##*/}([ \t]|\$)/ { print \$0; exit }" \
        "$BASH_COMPLETION" )
    # prune to leave nothing but the -X spec
    xspec=${xspec#*-X }
    xspec=${xspec%% *}

    local -a toks
    local tmp

    toks=( ${toks[@]-} $(
        compgen -d -- "$(quote_readline "$cur")" | {
        while read -r tmp; do
            # see long TODO comment in _filedir() --David
            printf '%s\n' $tmp
        done
        }
        ))

    # Munge xspec to contain uppercase version too
    eval xspec="${xspec}"
    eval xspec="!*.txt" #<---- HERE add your regex, that's the only line changed
    local matchop=!
    if [[ $xspec == !* ]]; then
        xspec=${xspec#!}
        matchop=@
    fi
    [[ ${BASH_VERSINFO[0]} -ge 4 ]] && \
        xspec="$matchop($xspec|${xspec^^})" || \
        xspec="$matchop($xspec|$(printf %s $xspec | tr '[:lower:]' '[:upper:]'))"

    toks=( ${toks[@]-} $(
        eval compgen -f -X "!$xspec" -- "\$(quote_readline "\$cur")" | {
        while read -r tmp; do
            [ -n $tmp ] && printf '%s\n' $tmp
        done
        }
        ))
    [ ${#toks[@]} -ne 0 ] && _compopt_o_filenames
    COMPREPLY=( "${toks[@]}" )
}

请注意新部分32号线:

eval xspec="!*.txt" 

该语句稍后用于compgen删除所有与正则表达式不匹配的条目。我不建议编辑该文件/etc/bash_completion。相反,使用上面的内容和source文件(如果需要)创建一个新文件:

source /path/to/file

现在,shell 中由函数完成的所有命令/应用程序 _filedir_xspec()现在仅使用文件名完成*.txt

答案2

您也可以仅将其用于某些程序或您的自定义脚本或命令。

要仅显示txt建议中具有扩展名的文件,只需编写一个 shell 脚本并source在当前会话中:

# Autocomplete file /path/to/file/sample-completion.sh
# for the command `sample`
_sample(){
   COMPREPLY=($(compgen -f -X "!.*[.][tT][xX][tT]$" -- "$2"))
}

complete -F _sample sample

并通过调用获取它:

$ source /path/to/file/sample-completion.sh

在此代码中,$2当前单词正在完成。该-- "$2"零件使compgen仅过滤掉包含当前正在完成的单词的建议并将其放入COMPREPLY。另外,该-f选项告诉compgen仅查找当前目录中的文件。最后但并非最不重要的-X选项是过滤模式(看这里)排除匹配文件名。位于!模式的开头否定这种行为。结果,仅.txt显示具有扩展名的文件。$正则表达式末尾的符号查找以给定模式结尾的匹配项。这[.]意味着它将查找文字点,而不仅仅是任何字符 - 这是正则表达式中点的默认含义。该[tT][xX][tT]部分表示模式将匹配所有这些情况:“txt, txT, tXt, tXT, Txt, TxT, TXT, TXt”。

答案3

倚在接受的答案来自@chaos,我建议这个功能修补需要时现有的完成功能:

patchFDxspec(){
  . <(type _filedir_xspec | sed -e '1d;s/\(eval xspec="\).*$/&\n\1!*.txt";/');
}

执行此函数将为_filedir_xspec当前会话打补丁。

如果您需要除 之外的其他扩展名.txt,您可以修改该函数以将所需的后缀设为$1.

相关内容