Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在bash中启用默认文件完成_Bash - Fatal编程技术网

如何在bash中启用默认文件完成

如何在bash中启用默认文件完成,bash,Bash,假设我有一个名为“foo”的命令,它接受一个参数(“加密”或“解密”),然后是一个文件列表。我想编写一个bash完成脚本,帮助处理第一个参数,然后为其他参数启用标准文件完成。我能做的最接近的事情是: complete -F _foo foo function _foo() { local cmds cur if [ $COMP_CWORD -eq 1 ] then cur="${COMP_WORDS[1]}" cmds=("encrypt

假设我有一个名为“foo”的命令,它接受一个参数(“加密”或“解密”),然后是一个文件列表。我想编写一个bash完成脚本,帮助处理第一个参数,然后为其他参数启用标准文件完成。我能做的最接近的事情是:

complete -F _foo foo

function _foo()
{
    local cmds cur
    if [ $COMP_CWORD -eq 1 ]
    then
        cur="${COMP_WORDS[1]}"
        cmds=("encrypt decrypt")
        COMPREPLY=($(compgen -W "${cmds}" -- ${cur}) )
    else
        COMPREPLY=($(compgen -f ${COMP_WORDS[${COMP_CWORD}]} ) )
    fi
}

这将正确执行第一个参数,并将从当前目录中为后续参数选择一个文件名。但是假设当前目录包含一个子目录栏,其中包含一个文件baz.txt。键入ba TAB TAB后,完成结果为“bar”(在“r”后面的空格),并准备好选择下一个参数。我想要的是标准的bash完成,结果是“bar/”(斜杠后面没有空格),可以在子目录中选择一个文件。有没有办法做到这一点?

bash文档可能有点神秘。最简单的解决方案是更改完成函数绑定:

complete -o filenames -F _foo foo
这意味着函数返回文件名(包括目录),并启用对结果的特殊处理

(我想说明的是,文档中没有明确说明,这可以有效地按照您的完成功能设置对
进行全面的后置处理[]
;并且当应用于
compgen
时,其中包含的一些
-o
选项似乎没有任何效果。)

通过使用以下命令,可以更接近正常的bash行为:

 complete -o filenames -o bashdefault -F _foo foo
这会让你重新完成

然而,上述方法存在两个问题:

  • 如果您有一个名为“encrypt”或“decrypt”的目录,则关键字的扩展将增加一个尾随“/”
  • $VARIABLE
    扩展将不起作用,
    $
    将变为
    \$
    ,以便更好地将文件名与
    $
    匹配。类似地,
    @host
    扩展也无法工作
我发现处理此问题的唯一方法是处理
compgen
输出,而不是依赖“文件名”后处理:

_foo()
{
    local cmds cur ff
    if (($COMP_CWORD == 1))
    then
        cur="${COMP_WORDS[1]}"
        cmds="encrypt decrypt"
        COMPREPLY=($(compgen -W "$cmds" -- "$cur"))
        COMPREPLY=( "${COMPREPLY[@]/%/ }" )   # add trailing space to each
    else
        # get all matching files and directories
        COMPREPLY=($(compgen -f  -- "${COMP_WORDS[$COMP_CWORD]}"))

        for ((ff=0; ff<${#COMPREPLY[@]}; ff++)); do
            [[ -d ${COMPREPLY[$ff]} ]] && COMPREPLY[$ff]+='/'
            [[ -f ${COMPREPLY[$ff]} ]] && COMPREPLY[$ff]+=' '
        done
    fi
}

complete -o bashdefault -o default -o nospace -F _foo foo
\u foo()
{
本地cmds cur ff
如果($COMP_CWORD==1))
然后
cur=“${COMP_WORDS[1]}”
cmds=“加密-解密”
COMPREPLY=($(compgen-W“$cmds”--“$cur”))
COMPREPLY=(“${COMPREPLY[@]/%/}”)#在每个
其他的
#获取所有匹配的文件和目录
COMPREPLY=($(compgen-f--“${COMP_WORDS[$COMP_CWORD]}”))

对于((ff=0;ff我知道这有点晚了,但我在这里找到了一个解决方案:

基本上,您可以使用
complete-obashdefault-obashdault
,当您想要恢复到默认的bash完成时,您可以设置
COMPREPLY=()
。下面是一个示例:

complete -o bashdefault -o default -F _foo foo
_foo() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    if (( $COMP_CWORD == 1 )); then
        COMPREPLY=( $(compgen -W 'encrypt decrypt' -- "$cur") )
    else
        COMPREPLY=()
    fi
}

+1非常整洁。它恢复为readline默认值而不是bash,这并不是因为它会影响操作,而是您丢失了bash默认完成($,~,@)。我认为
compopt-obashdefault
(bash-4.0)在这方面会有所帮助。
${COMPREPLY[@]/%/}
添加了一个空格?bash是一种非常丑陋的语言。